使用invokeLater或SwingWorker从另一个线程更新Swing组件

时间:2010-02-11 21:06:07

标签: java swing multithreading

我正在开发一个小应用程序,它将具有Swing GUI。 App正在另一个线程中执行IO任务,当该线程完成时,GUI应该相应地更新以反映线程的操作结果。在(工作者,非GUI)中运行的类具有在构造函数中传递给它的对象,该对象将用于更新GUI,因此我不需要将GUI内容放在非GUI类中,而是传递对象以更新GUI那个班。 据我所知,在这里阅读表格,(线程/摆动)更新(更改)Swing GUI的安全选项是使用基本相同的javax.swing.SwingUtilities.invokeLater()javax.swing.SwingUtilities.invokeLaterWait()和/或javax.swing.SwingWorker()事情。

Swing的所有线程问题对我来说有点困惑,但我需要使用线程在GUI应用程序中执行任何有意义的操作,而不是在EDT中处理时挂起GUI,所以我现在感兴趣的是:

  1. invokeLaterinvokeLaterWait是否向EDT发送消息并等待它完成处理该呼叫之前的消息时执行此操作?

  2. 从Swing线程安全方面来看是否正确,做这样的事情:

    interface IUPDATEGUI {  
      public void update();  
    }  
    
    // in EDT/where I can access components directly    
    class UpdateJList implements IUPDATEGUI {    
      public void update() {    
        // update JList...    
        someJList.revalidate();    
        someJList.repain();    
      }    
    }    
    
    class FileOperations implements Runnable {  
      private IUPDATEGUI upObj;  
      List<File> result = new ArrayList<File>; // upObject is accessing this  
    
      public void FileOperations(IUPDATEGUI upObj) {
        this.upObj = upObj;
      }
    
      private void someIOTask() {
        // ...
        // IO processing finished, result is in "result"
      }
    
      public void run() {
        someIOTask();
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            upObj.update();  // access result and update JList
          }
        }; );
      }
    }
    
  3. 如果这不正确,应该怎么做?

    如果可以的话,我宁愿使用invokeLater而不是SwingWorker,如果可能的话,因为我不需要改变我的整个班级,而且它在某种程度上更加整洁/独特(如发送一个Win32应用程序中的消息。)

    提前致谢。

3 个答案:

答案 0 :(得分:5)

使用invokeLater()invokeAndWait()将Runnable参数传递到等待在EDT中执行的队列。因此,当EDT能够处理请求时,调用invokeLater()将导致Runnable在EDT中执行。 invokeAndWait()只是等待(在调用线程中),直到执行完毕。

如果您想要执行在执行结束时或处于中间状态时通知EDT的后台任务,则使用SwingWorker是理想的选择。一个例子是将进程的当前进度传递给JProgressBar。

对于您的示例,似乎SwingWorker是一个更好的选择,但如果您不想过多地更改代码,那么在完成该过程时调用invokeLater()就可以了。

答案 1 :(得分:3)

我建议在java 7之前不要使用invokeAndWait。我发现这种方法的虚假唤醒可能会导致非常痛苦的错误。对我来说,它导致了一些非常罕见且难以调试的空指针异常。

http://bugs.sun.com/view_bug.do?bug_id=6852111

从java 7 b77开始修复。

答案 2 :(得分:0)

invokeLater没问题。这会将调用放入AWT事件队列中,以便在适当的时候在EDT中执行。您的程序将继续运行,并且不会等待您的可调用程序被调用。