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

问题描述 投票:0回答:4

经过多年的 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()
    方式?当我尝试时,我看不出有什么不同。
  • 这两种方式有什么区别?

感谢您阅读我的文章和您的回答。

java swing program-entry-point swingutilities invokelater
4个回答
24
投票

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

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

以及来自 事件调度线程

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

另请参阅维基百科上的事件调度线程


15
投票

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


3
投票

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


1
投票

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

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

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


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

如果您不使用 Swing/AWT(例如 JavaFX 应用程序或终端应用程序),则在 main 方法上使用

SwingUtilities.invokeLater()
是没有意义的。

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

© www.soinside.com 2019 - 2024. All rights reserved.