java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewJFrame().setVisible(true);
}
});
请告诉我上面的代码实际上做了什么。我正在寻找逐行解释。特别是第一行并告诉我为什么要使用它,以及在什么情况下我们必须使用它。
答案 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将阻止进程退出。
另一个很好的解释:
答案 2 :(得分:2)
这是一段代码,指示稍后执行(有时称为deferred)。内部类(new Runnable() {...}
)基本上允许您传递将要运行的代码块。 invokeLater
method保证将运行代码块,但不保证何时。有时候让某些代码立即运行是不安全的,而且你自己也很难做多线程。所以Java提供了这种实用工具方法来安全地运行代码。代码将很快运行,但直到可以安全运行。
答案 3 :(得分:1)
invokeLater
调用会将指定的runnable放在队列中以便稍后处理。也就是说,当run()
方法调用返回时,invokeLater
方法中的代码尚未运行。
此类代码有两种典型用例。
将匿名类作为参数传递给invokeLater
调用。它与此代码相同。
private void foo()
{
java.awt.EventQueue.invokeLater(new JFrameCreator());
}
private class JFrameCreator implements Runnable
{
public void run() {
new NewJFrame().setVisible(true);
}
}
答案 4 :(得分:1)
invokeLater()方法将Runnable对象作为其参数。它将该对象发送到事件派发线程,该线程执行run()方法。这就是为什么run()方法执行Swing代码总是安全的。
-IvarD