解释下面的代码是做什么的?

时间:2011-02-05 18:42:58

标签: java swing concurrency runnable

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

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

5 个答案:

答案 0 :(得分:27)

在此示例中,您将看到从Runnable派生的任何类。这个匿名类重写了runnable接口的run方法。然后实例化此匿名类并将其传递给EventQueue.invokeLater方法,该方法是一种静态方法。此方法将对象追加到...... well ... eventQueue。在EvenQueue中有很多事件,比如键盘事件或鼠标事件或其他什么。有一个Thread继续轮询来自此队列的数据。一旦该Thread到达在此处实例化的匿名类,它将执行run()方法,该方法将实例化NewJFrame类的Object并将其设置为可见。

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

答案 1 :(得分:4)

单线程模型和EDT

大多数现代UI库采用single-thread-model。这意味着,UI组件上的所有操作必须在同一个单独的线程上完成。为什么?这是因为允许从多个线程更新UI组件将导致most Swing object methods are not "thread safe"以来的混乱。为简单起见,效率和稳健性,采用单线程模型。

在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 explanation

一篇有趣的文章: Multi-threaded toolkit, a failed dream?

答案 2 :(得分:2)

这是一段代码,指示稍后执行(有时称为deferred)。内部类(new Runnable() {...})基本上允许您传递将要运行的代码块。 invokeLater method保证将运行代码块,但不保证何时。有时候让某些代码立即运行是不安全的,而且你自己也很难做多线程。所以Java提供了这种实用工具方法来安全地运行代码。代码将很快运行,但直到可以安全运行。

答案 3 :(得分:1)

invokeLater调用会将指定的runnable放在队列中以便稍后处理。也就是说,当run()方法调用返回时,invokeLater方法中的代码尚未运行。

此类代码有两种典型用例。

  1. 当前正在执行的代码在后台线程中运行。后台线程无法访问大多数swing API。阅读更多here的原因。如果当前线程已经是UI线程,则没有理由可以安全地删除该调用。
  2. 必须退出当前块,即代码到达最后一个括号。这可能会导致资源被释放等等。这并不常见。
  3. 将匿名类作为参数传递给invokeLater调用。它与此代码相同。

    private void foo()
    {
      java.awt.EventQueue.invokeLater(new JFrameCreator());
    }
    private class JFrameCreator implements Runnable
    {
      public void run() {
        new NewJFrame().setVisible(true);
      }
    }
    

答案 4 :(得分:1)

Source

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

-IvarD