23

经过多年的 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

4 回答 4

22

文档解释了原因。从初始线程

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

和来自事件调度线程

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

于 2013-03-08T20:00:03.207 回答
13

因为VM启动的线程“main”不是事件调度线程

于 2013-03-08T20:08:57.317 回答
3

API 中的一些 Swing 组件不是线程安全的,这意味着它们可能会导致死锁等问题,因此最好使用 Swing 提供的 Event Dispatcher 线程而不是来自主线程或任何其他线程来创建和更新此类 Swing 组件从 main 创建的线程。

于 2013-09-11T12:04:29.100 回答
1

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

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

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


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

SwingUtilities.invokeLater()如果您不使用 Swing/AWT(例如 JavaFX 应用程序或终端应用程序),则在 main 方法上使用是没有意义的。

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

于 2021-03-17T12:02:59.763 回答