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

Posted

技术标签:

【中文标题】为啥在 main 方法中使用 SwingUtilities.invokeLater?【英文标题】:Why to use SwingUtilities.invokeLater in main method?为什么在 main 方法中使用 SwingUtilities.invokeLater? 【发布时间】:2013-02-24 11:24:01 【问题描述】:

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

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

【问题讨论】:

【参考方案1】:

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

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

来自The Event Dispatch Thread

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

【讨论】:

我明白了,很有趣。感谢您提供链接并强调了重要内容。 是否有一个清晰的小例子说明如果 main 直接调用 runProgram() 会出现什么问题?据我所知,这里显示的链接参考资料和摘录似乎都没有回答这个问题。【参考方案2】:

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

【讨论】:

【参考方案3】:

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

【讨论】:

【参考方案4】:

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

是的,与 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 中执行此操作或主线程(有关此主题的讨论,请参阅 this post)。

【讨论】:

以上是关于为啥在 main 方法中使用 SwingUtilities.invokeLater?的主要内容,如果未能解决你的问题,请参考以下文章

无法在 main() 方法中实例化字段(实例变量)。为啥??爪哇

Main 方法在执行过程中等待线程完成。为啥?

为啥 &a 在 main() 和其他方法中显示不同的值?

为啥包含 main 方法的类没有实例化并且在 Java 中仍然可以?

为啥单例对象创建的scala程序不需要静态main方法?

java中为啥要把main方法定义为一个static方法