Java 中的主线程与 UI 线程
Posted
技术标签:
【中文标题】Java 中的主线程与 UI 线程【英文标题】:Main Thread vs. UI Thread in Java 【发布时间】:2011-11-01 16:27:28 【问题描述】:在此处作为答案给出的许多 Swing sn-ps 中,有一个来自 main
方法的对 SwingUtilities#invokeLater
的调用:
public class MyOneClassUiApp
private constructUi()
// Some Ui related Code
public static void main(String[] args)
SwingUtilities.invokeLater(new Runnable()
public void run()
new MyOneClassUiApp().constructUi();
);
但是根据Threads and Swing article,从主线程构造UI是安全的:
一些方法是线程安全的:在 Swing API 文档中, 线程安全方法标有以下文本:
这个方法是线程安全的,虽然大多数 Swing 方法不是。
应用程序的 GUI 通常可以构建并显示在主界面中 thread:下面的典型代码是安全的,只要没有组件 (摇摆或其他)已实现:
public class MyApplication
public static void main(String[] args)
JFrame f = new JFrame("Labels");
// Add components to
// the frame here...
f.pack();
f.show();
// Don't do any more GUI work here...
那么,通过SwingUtilities#invokeLater
在 main 中构造 UI 是否有真正的(线程安全)理由,或者这只是一种习惯,要记住在其他情况下这样做?
【问题讨论】:
是的,你必须在所有情况下都包装 main 方法,是的,大多数 JComponents 都是线程安全的,但对于它们的嵌套和继承方法无效,仅此而已,抱歉,也许这个.
另见Q&A,它检查“为什么 GUI 是单线程的?”
【参考方案1】:
“Swing 单线程规则:Swing 组件和模型应该仅从事件调度线程中创建、修改和查询。”—Java Concurrency in Practice ,还讨论了here 和here。如果您不遵守此规则,则您无法可靠地构造、修改或查询任何可能假定您确实遵守该规则的组件或模型。一个程序可能看起来正常工作,但在不同的环境中却神秘地失败了。由于违规行为可能不明显,请使用here 提到的方法之一验证正确使用。
【讨论】:
【参考方案2】:我认为使用SwingUtiltities.invokeLater()
只是一种更简单的异步执行代码的方法。有时某些应用程序需要它:例如,您可以同时创建 2 个单独的窗口。而已。
【讨论】:
这不仅仅是一种异步执行某些代码的方法。它在 Event Dispatcher Thread 中执行给定的Runnable
,并且根据情况可能会有所不同
@Luismahou,谢谢。我不知道这个区别。在事件调度线程中执行代码有什么好处?我只知道缺点:如果任务由于某种原因需要很长时间,它可能会阻止其他事件的调度。
一般来说 Swing 相关的代码应该在 EDT 中执行。为什么?仅仅是因为 Swing 不支持多线程。例如,如果您在与 EDT 不同的线程中更改 JLabel 的文本,而 EDT 正在执行同一 JLabel 的 paint()
方法,则可能会发生意外情况。关于缺点,SwingWorker是官方的解决方案,有助于在EDT之外执行非UI代码。
注意:JLabel.setText 不是一个很好的例子,因为它默认在 EDT 中运行(以及其他一些)。但如有疑问,请在 EDT 中运行。【参考方案3】:
在 main 方法中创建 Swing UI 是安全的,因为在设置 UI 之前其他组件将如何显示?只要你还没有在屏幕上扔一些东西,你就没事了。换句话说,这会很糟糕:
public class MyApplication
public static void main(String[] args)
JFrame f = new JFrame("Labels");
// Add components to
// the frame here...
f.pack();
f.show();
// now make another frame:
JFrame f2 = new JFrame("Labels2");
// Add components to the 2nd frame here...
f2.pack();
f2.show();
如果您执行了上述操作,您将启动并运行 JFrame f
,然后您将在事件调度线程 (EDT) 之外添加 Swing UI 组件。 invokeLater
在 EDT 上运行代码 - 如果您想更加安心,使用它不会有什么坏处。
【讨论】:
关于您的示例 - 它非常接近我给出的第二个示例(来自 Java 的站点)。所以你说这是关于“安心”,对吧? 是的,因为那时(只需输入main
)屏幕上还能实现什么?没什么,因为你还没有做任何事情!除了那种非常特殊的情况,您必须非常小心,只在 EDT 上执行 Swing 代码。就个人而言,我从事 Swing 编程多年,从未遇到过直接从 main
创建 UI 的问题。
我只玩了几年的 Swing,但我也从来没有遇到过问题。我想我没有运行复杂的 UI 应用程序......以上是关于Java 中的主线程与 UI 线程的主要内容,如果未能解决你的问题,请参考以下文章
在主线程上处理大型全局对象时如何不阻止来自工作线程的主 UI 线程