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);
}