何时使用SwingUtilies.invokeAndWait / invokeLater

时间:2011-12-31 10:34:01

标签: java multithreading swing event-dispatch-thread concurrency

我在某地读到,对于影响gui视觉效果的任何线程,它应该使用SwingUtilities.invokeAndWait / invokeLater在EDT中运行

对于基本的gui,是否有必要使用invokeAndWait将new SwingGUI().setVisible(true);之类的东西放在EDT的行中?只是为了显示?

这算得上吗?

4 个答案:

答案 0 :(得分:9)

对你的问题的简短回答是:是的,甚至在美国东部时间调用setVisible也是如此。要确定当前线程是否为EDT,您可以使用EventQueue#isDispatchThread方法

一些参考链接:

编辑: 在阅读了我提供的链接后,似乎Oracle网站上的一些文章已经过时了,因为他们仍然可以在另一个线程上创建Swing组件。这里有一个stackoverflow question,其中包含一些很好的答案以及博客文章和关于“新”政策的文章的链接(几年前的新内容)

答案 1 :(得分:3)

是的,如果您触摸Swing对象,则必须在EDT上执行此操作。在大多数情况下,您已经在那里,但如果没有,请使用SwingUtilities类。原因是Swing类不是多线程的,因此如果您在其他线程上访问它,可能会导致令人讨厌的问题。而且setVisible()可能会在幕后做很多事情来制作一些东西(比如重新铺设东西)。更安全。

答案 2 :(得分:0)

从您的

调用的任何内容
public static void main(String[] agrs) {

直接(没有产生另一个线程或使用invokeLater)正在主线程上运行。

在EDT(由用户输入触发)访问(同时)访问GUI主对象时,可能会导致线程问题。调用invokeLater会导致任务(runnables)在EDT上运行,从而阻止其他EDT任务同时访问,即。按钮按等。

如果可以确定EDT不忙(在第一个窗口设置为可见(真)之前),则可以从主线程访问GUI。如果您可以确定EDT没有参考您正在处理的组件(它超出了EDT的范围),即。在将其添加到任何容器之前,您可以从主线程访问它而EDT无法同时访问它,因为EDT无法访问它。

答案 3 :(得分:-1)

访问Swing对象的所有内容都应该通过Event Dispatch Thread(EDT)来实现。这有一个小例外(我将在后面提到)。 EDT的目的是处理由于IO(鼠标和键盘事件)而可能发生的任何事件。很多时候这可能意味着改变GUI的布局。 Swing没有开发为线程安全的,这意味着如果两个线程试图同时修改同一个组件,那么最终可能会出现损坏的GUI。由于已经有一个已知的线程要访问Swing组件(EDT),因此没有其他线程可以尝试修改它们甚至读取它们的状态。

现在,在特殊情况下,您可以在EDT之外操作Swing对象。在任何组件变得可见之前,IO不可能触发事件。因此,主线程可以设置Swing GUI,然后将单个JFrame设置为可见。由于现在可以发生可见的帧IO事件,并且主线程不应该尝试修改任何更多的Swing组件。应该只使用这个选项来启动GUI,实际上只有玩具问题。

我所说的是以下情况很好,如果你只是玩弄东西,不会引起问题。

public static void main(String[] args) {
    // create components
    JFrame f = new JFrame();
    ...

    // do layout and other bits of setup


    // show gui to user
    f.setVisible(true);
}