经过多年的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()
方式?我试了一下,没发现有什么不同。 - 这两种方式有什么区别?
谢谢你的阅读和你的回答。
文档解释了原因。来自Initial Threads
为什么初始线程不直接创建GUI本身?因为几乎所有创建或与Swing组件交互的代码都必须运行在事件分派线程上。
和来自事件调度线程
一些Swing组件方法在API规范中被标记为"线程安全";这些可以从任何线程安全地调用。所有其他Swing组件方法必须从事件分派线程调用。忽略此规则的程序可能在大多数情况下正常工作,但会发生难以重现的不可预测的错误。
因为由VM启动的线程"main"不是事件调度线程。
API中的一些Swing组件不是线程安全的,这意味着它们可能会导致死锁等问题,因此最好使用Swing提供的事件分派器线程来创建和更新这些Swing组件,而不是从主线程或从主线程创建的任何其他线程。
虽然以上答案都是正确的,但我认为他们缺乏正确的解释。
是的,所有与Swing交互的事情(创建UI、更新UI、添加新组件或布局等)都应该在AWT事件调度线程上完成(关于这个主题的更多信息,请参阅这篇文章)。
SwingUtilities.invokeLater()
将您的代码放在事件调度线程(EDT)的FIFO队列中,因此无论何时它完成了它正在做的其他任务,它都将从EDT执行。
话虽如此, EDT应该专门用于运行与swing相关的任务,这些任务可以快速执行(如果阻塞EDT,则阻塞整个UI)。
如果你不使用Swing/AWT(例如JavaFX应用程序或终端应用程序),在main方法上使用SwingUtilities.invokeLater()
是没有意义的。
如果你想执行一些与Swing完全无关的任务,但它们需要启动Swing(例如在mvc类应用程序中启动模型和控制器),你可以从EDT或主线程中完成(参见这篇文章关于这个主题的讨论)。