15
java.awt.EventQueue.invokeLater(new Runnable() {
    public void run() {
        new NewJFrame().setVisible(true);
    }
});

请告诉我上面的代码实际上做了什么。我正在寻找逐行解释。特别是第一行,告诉我为什么要使用它以及在什么情况下我们必须使用它。

4

5 回答 5

28

在此示例中,您会看到一个派生自 Runnable 的任意类。这个匿名类覆盖了接口runnable的run方法。然后将这个匿名类实例化并传递给 EventQueue.invokeLater 方法,该方法是一个静态方法。此方法将对象附加到......好吧...... eventQueue。EvenQueue 中有许多事件,例如键盘事件或鼠标事件等。有一个线程不断地从这个队列中轮询数据。一旦该线程到达此处实例化的匿名类,它将执行 run() 方法,该方法将实例化 NewJFrame 类的 Object 并将其设置为可见。

做这个复杂的重点是新的 JFrame().setVisible(true) 部分不是在主线程中执行,而是在事件调度线程中执行。在 Swing 中,您必须在事件分派线程中执行所有修改用户界面的代码。

于 2011-02-05T18:50:41.987 回答
4

单线程模型和 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 解释

一篇有趣的文章: 多线程工具包,一个失败的梦想?

于 2016-06-16T02:44:57.257 回答
2

这是指示稍后执行的代码块(有时称为deferred)。内部类 ( new Runnable() {...}) 本质上允许您传递将要运行的代码块。该invokeLater方法保证代码块将运行,但不保证何时运行。有时让某些代码立即运行是不安全的,而且它过于冗长而无法自己执行多线程。所以Java提供了这个实用方法来安全地运行代码。代码将很快运行,但在安全之前不会运行。

于 2011-02-05T18:52:55.403 回答
1

invokeLater调用会将指定的可运行对象放入队列中以供稍后处理。也就是说,当方法调用返回时,方法内部的代码run()还没有运行。invokeLater

这种类型的代码有两个典型的用例。

  1. 当前执行的代码在后台线程中运行。后台线程无法访问大部分 swing API。在此处阅读更多内容以了解其原因。如果当前线程已经是 UI 线程,则没有理由,可以安全地删除调用。
  2. 必须退出当前块,即代码到达最后一个大括号。这可能会导致资源被释放等等。这并不常见。

匿名类作为参数传递给invokeLater调用。它与此代码相同。

private void foo()
{
  java.awt.EventQueue.invokeLater(new JFrameCreator());
}
private class JFrameCreator implements Runnable
{
  public void run() {
    new NewJFrame().setVisible(true);
  }
}
于 2011-02-05T18:58:20.977 回答
1

来源

invokeLater() 方法将 Runnable 对象作为其参数。它将该对象发送到事件调度线程,该线程执行 run() 方法。这就是为什么 run() 方法执行 Swing 代码总是安全的。

-IvarD

于 2011-05-03T10:09:51.900 回答