5.4.4 SecondaryLoop接口

在介绍SwingWorker类的时候曾经提到,如果希望当前线程等待SwingWorker类的对象的工作线程运行完成,可以调用get方法,该方法会阻塞当前线程直到SwingWorker类的对象中的任务完成或被取消。如果调用get方法的线程是事件分发线程,那么会造成用户界面失去响应,有时候确实需要等待某个任务完成才能进行下一步操作。为了解决这种同步调用和事件分发线程处理之间的矛盾,Java 7对AWT中的事件处理进行了增强,添加一个额外的事件队列。这个新的事件队列既可以阻塞当前线程以等待操作完成,又可以继续处理事件队列中的事件,并且不会造成界面失去响应。这个新的事件队列由java.awt.SecondaryLoop接口来表示,通过EventQueue类的对象的createSecondaryLoop方法来创建具体的实例。在创建出SecondaryLoop接口的实现对象之后,可以调用该对象的enter方法来阻塞当前线程并进入新的事件处理循环中;当要等待的操作完成之后,可以调用exit方法来退出这个新的事件处理循环,同时恢复被enter方法阻塞的线程的执行。

在需要等待操作完成的时候,都应该使用SecondaryLoop接口,它可以避免用户界面失去响应的问题。代码清单5-12给出了一个示例,通过一个线程来模拟需要等待完成的操作。在线程启动之后,通过SecondaryLoop接口的enter方法来阻塞事件分发线程;而在工作线程完成任务之后,通过SecondaryLoop接口的exit方法来恢复事件分发线程的执行。在工作线程的运行过程中,用户界面产生的其他事件仍然可以得到处理。

代码清单5-12 SecondaryLoop接口的使用示例


private static class WorkerThread extends Thread{

private SecondaryLoop loop;

public WorkerThread(SecondaryLoop loop){

this.loop=loop;

}

public void run(){

try{

Thread.sleep(5000);

}catch(InterruptedException ex){

}

loop.exit();

}

}

public void useLoop(){

JFrame frame=new JFrame();

frame.setSize(400,300);

frame.addMouseListener(new MouseAdapter(){

public void mouseClicked(MouseEvent e){

EventQueue queue=Toolkit.getDefaultToolkit().getSystemEventQueue();

SecondaryLoop loop=queue.createSecondaryLoop();

WorkerThread thread=new WorkerThread(loop);

thread.start();

loop.enter();

}

});

frame.setVisible(true);

}