在SwingUtilities.invokeLater里放什么(而不是放)?

时间:2016-02-24 21:31:24

标签: java multithreading swing awt

在Swing-land中,从静态main方法中调用SwingUtilities.invokeLater(Runnable)似乎是一种常见/良好的做法:

public class MyApp extends JFrame {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            void run() {
                // What to do here?!?
            }
        });

        // And what to do here?!?
    }
}

根据该方法的JavaDocs

  

导致doRun.run()在AWT事件派发线程上异步执行。这将在处理完所有挂起的AWT事件后发生。当应用程序线程需要更新GUI时,应使用此方法。在下面的示例中,invokeLater调用在事件派发线程上对Runnable对象doHelloWorld进行排队,然后打印一条消息。

但即使在阅读完这篇文章后,我仍然感到困惑的是({em>具体)代码放在这个Runnable中(我们传递给invokeLater) ,以及放入其中的代码。有什么想法吗?

2 个答案:

答案 0 :(得分:2)

我认为camickr基本上已经回答了核心问题

进行(主要)重新迭代,进入可能改变UI或以某种方式直接或间接与UI交互的任何内容,外部可以进行任何其他操作,尤其是任何阻塞或长时间运行的代码

如果你看过我的任何Swing相关答案,你会看到这种模板(是的,它是我在Netbeans中设置的代码模板)

import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

}
  你可以举几个具体的例子吗?

如果它可能会以任何方式改变UI(直接或间接地 - 更改组件的属性,更新布局等)。一般的经验法则是,任何基于Swing的组件都不是线程安全的,你不应该有任何问题,开始第二次猜测这个规则,你会遇到麻烦,也许不是今天,但很可能明天。

问题是,当组件可能触发对EDT的更新时,API几乎没有保证,这正是您真正关心的问题。如有疑问,请加入EDT。

API中很少有被认为是线程安全的方法,repaint是最明显的,但就个人而言,我只是将整个API视为不是线程安全的,它节省了大量的猜测。

如果您知道有长时间运行或可能阻塞的操作(文件IO,网络呼叫等等),那么这些操作需要在EDT之外进行(可能使用SwingWorker或Swing {{ 1}}视情况而定),但是当您想要更新UI(例如更改标签文本或更新进度条)时,这些调用必须在EDT的上下文中进行。

首先仔细看看Concurrency in Swing

答案 1 :(得分:0)

对于未来的人来说,我想出来了,尽管文档并没有以一种对Swing新手来说显而易见的方式来解释这一点:

  • 当文档或博客/文章/人说“任何触及用户界面的”时,这会转换为:“ javax.swing.*下的Swing类的任何操作”。因此,使用JFrameJPanel或任何JComponents执行任何操作。所有这些内容都应该在您从应用的Runnable方法内传递到SwingUtilities.invokeLater的{​​{1}}内执行。所以基本上你最终会得到一个巨大的,整体的main来完成所有的UI代码操作。奇怪和反MVC恕我直言。
  • 如果您有一个漫长的过程,您应该从该过程中删除所有Swing代码并将其传递到您自己的Runnable