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