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);
}
});
请告诉我上面的代码实际上做了什么。我正在寻找逐行解释。特别是第一行,告诉我为什么要使用它以及在什么情况下我们必须使用它。
在此示例中,您会看到一个派生自 Runnable 的任意类。这个匿名类覆盖了接口runnable的run方法。然后将这个匿名类实例化并传递给 EventQueue.invokeLater 方法,该方法是一个静态方法。此方法将对象附加到......好吧...... eventQueue。EvenQueue 中有许多事件,例如键盘事件或鼠标事件等。有一个线程不断地从这个队列中轮询数据。一旦该线程到达此处实例化的匿名类,它将执行 run() 方法,该方法将实例化 NewJFrame 类的 Object 并将其设置为可见。
做这个复杂的重点是新的 JFrame().setVisible(true) 部分不是在主线程中执行,而是在事件调度线程中执行。在 Swing 中,您必须在事件分派线程中执行所有修改用户界面的代码。
单线程模型和 EDT
大多数现代 UI 库都采用single-thread-model
. 这意味着,对 UI 组件的所有操作都必须在同一个线程上完成。为什么?这是因为允许从多个线程更新 UI 组件会导致混乱,因为大多数 Swing 对象方法都不是“线程安全的”。为了简单、高效和健壮,采用单线程模型。
在 Swing 中,提供服务的线程single-thread-model
称为Event Dispatching Thread,即 EDT。它不是由 Swing 提供的。它由Abstract Window Toolkit即 AWT 提供。
工作线程与 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 解释
一篇有趣的文章: 多线程工具包,一个失败的梦想?
这是指示稍后执行的代码块(有时称为deferred)。内部类 ( new Runnable() {...}
) 本质上允许您传递将要运行的代码块。该invokeLater
方法保证代码块将运行,但不保证何时运行。有时让某些代码立即运行是不安全的,而且它过于冗长而无法自己执行多线程。所以Java提供了这个实用方法来安全地运行代码。代码将很快运行,但在安全之前不会运行。
该invokeLater
调用会将指定的可运行对象放入队列中以供稍后处理。也就是说,当方法调用返回时,方法内部的代码run()
还没有运行。invokeLater
这种类型的代码有两个典型的用例。
匿名类作为参数传递给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