java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewJFrame().setVisible(true);
}
});
请告诉我这段代码实际上做了什么。我需要逐行解释,特别是第一行,并告诉我为什么我们要使用它,在什么情况下我们必须使用它。java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewJFrame().setVisible(true);
}
});
请告诉我这段代码实际上做了什么。我需要逐行解释,特别是第一行,并告诉我为什么我们要使用它,在什么情况下我们必须使用它。Single-Thread-Model 和 EDT
大多数现代 UI 库采用了 single-thread-model
,这意味着所有对 UI 组件的操作必须在同一单线程上完成。为什么?因为允许从多个线程更新 UI 组件会导致混乱,因为大多数 Swing 对象方法不是“线程安全的”。为了简化、高效和强健,采用了 single-thread-model。
在 Swing 中,服务于 single-thread-model
的线程被称为Event Dispatching Thread,即 EDT。它不是由 Swing 提供的,而是由 Abstract Window Toolkit 提供的。
工作线程 vs UI 线程
一个非平凡的 GUI 应用程序通常有许多线程。在现代 GUI 应用程序中,可以有许多工作线程来执行一些不好的工作,但只有一个 UI 线程(Swing 称之为 EDT)来更新 GUI。工作线程通常需要在 GUI 中反映它们的工作进度,因此它们需要与 UI 线程进行通信。那么这种通信是如何发生的呢?
java.awt.EventQueue
通信通过一个消息队列模型发生,java.awt.EventQueue
是提供全局事件队列的类。这个全局事件队列作为与 EDT 通信的通道。EDT 从此 EventQueue 中获取消息并相应地更新 UI 组件。如果程序的其他部分要操纵 UI,则该代码部分应调用 EventQueue.invokeLater()
或 EventQueue.invokeAndWait()
将消息排入 EventQueue。EDT将处理在 EventQueue 中挂起的所有消息,并最终到达消息。
主线程
您的代码段通常驻留在 main()
线程中,main
线程可以视为一种 worker thread
。只有不是通过将消息发布到 EventQueue 来更新 GUI,而是初始化 GUI。无论如何,启动也可以被视为一种工作。
初始化 GUI 后,主线程将退出,EDT 将防止进程退出。
另一个好的解释:
Java Event-Dispatching Thread explanation
一个有趣的文章:
这是一段代码块,它被指示在稍后执行(有时被称为延迟)。内部类(new Runnable() {...}
)实际上允许您传递将要运行的代码块。invokeLater
方法保证代码块将被运行,但不保证何时运行。有时立即运行某些代码是不安全的,而且手动进行多线程编程过于冗长。因此Java提供了这个实用方法来安全地运行代码。代码将很快运行,但直到可以安全地运行为止。
invokeLater
调用将指定的可运行对象放入队列中以便稍后处理。也就是说,在invokeLater
方法调用返回时,run()
方法内部的代码尚未运行。
这种类型的代码有两个典型用例。
匿名类作为参数传递给invokeLater
调用。它与此代码相同。
private void foo()
{
java.awt.EventQueue.invokeLater(new JFrameCreator());
}
private class JFrameCreator implements Runnable
{
public void run() {
new NewJFrame().setVisible(true);
}
}
invokeLater() 方法以 Runnable 对象作为其参数。它将该对象发送到事件分派线程,该线程执行 run() 方法。这就是为什么始终可以安全地让 run() 方法执行 Swing 代码的原因。
-IvarD
public static void main(String args[]) {New JFrame().setVisible(true);}
- Martin