为什么在main方法中使用SwingUtilities.invokeLater?

时间:2013-03-08 19:47:42

标签: java swing main swingutilities invokelater

经过多年的Java编程,我总是习惯于创建这样的main()方法:

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

但是最近我从网上学习了一些代码并且有时看到这个代码而不是上面通常的main()

public static void main(String[] args) 
{
    SwingUtilities.invokeLater(new Runnable() 
    {
        public void run() 
        {
            runProgram();
        }
    });
}

我只是想知道:

  • 为什么要使用此而不是通常的main()方式?当我试一试时,我看不出任何差异。
  • 这两种方式有什么区别?

感谢您阅读我和您的答案。

4 个答案:

答案 0 :(得分:23)

文档解释了原因。来自Initial Threads

  

为什么初始线程不是简单地创建GUI本身?因为几乎所有创建Swing组件或与Swing组件交互的代码都必须在事件派发线程上运行。

The Event Dispatch Thread

  

一些Swing组件方法在API规范中标记为“线程安全”;这些可以从任何线程安全地调用。 必须从事件派发线程调用所有其他Swing组件方法。忽略此规则的程序可能在大多数情况下正常运行,但会遇到难以重现的不可预测的错误。

答案 1 :(得分:14)

因为VM启动的线程“main”不是事件派发线程

答案 2 :(得分:3)

来自API的一些Swing组件不是线程安全的,这意味着它们可能会导致一些问题,比如死锁,所以最好通过使用Swing提供的Event调度程序线程来创建和更新这样的swing组件,而不是来自主线程或从main创建的任何其他线程。

答案 3 :(得分:1)

虽然上面的答案都是正确的,但我认为他们缺乏正确的解释。

是的,与 Swing 交互的所有内容(创建 UI、更新 UI、添加新组件或布局等)都应始终在 AWT 事件调度线程上完成(有关更多信息,请参阅 this post主题)。

SwingUtilities.invokeLater() 将您的代码放在事件调度线程 (EDT) 的 FIFO 队列中,因此只要它完成了它正在执行的其他任务,就会从 EDT 执行它。


话虽如此,EDT 应该专门用于运行快速执行的 Swing 相关任务(如果您阻止 EDT,就会阻止整个 UI)。

如果您不使用 Swing/AWT(例如 JavaFX 应用程序或终端应用程序),则在主方法上使用 SwingUtilities.invokeLater() 毫无意义。

如果您想执行一些与 Swing 完全无关但需要启动 Swing 的任务(例如在类似 MVC 的应用程序中启动模型和控制器),您可以从 EDT 中执行或主线程(有关此主题的讨论,请参阅 this post)。