63

我最近开始学习和探索 Java 中 GUI 编程的基础知识。

编程了一段时间后,我只完成了后端工作或工作,因此我最接近用户界面的是命令控制台(我知道这很尴尬)。

我正在使用 Swing,据我所知,这意味着通过扩展我也在使用 AWT。

我的问题是基于这段代码:

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

我已经研究了一段时间,因为我想完全理解这段奇怪的代码,并且多次遇到“事件调度线程”这个术语。如果我错了,请纠正我,但据我所知;它与使用多个线程以及 Java Swing 如何解释这些线程有关。我还收集到,上面的代码用于确保所有线程在创建窗口之前都是“安全的”,因此 invokeLater?

我读过:

“您只能从事件调度线程调用对帧进行操作的方法”

并且只有在某些情况下,您才能从 main 方法调用对框架进行操作的方法。

有人可以向我解释一下事件调度线程到底是什么吗?

它与多个执行线程有何关系,以及从 main 方法调用这些线程是如何不安全的?还有为什么我们需要这个invokeLater?

我们不能像任何其他对象一样创建窗口吗?

我在研究中遇到了一些障碍,因为我没有掌握这些关系和想法。

附带说明一下,我喜欢将我的知识建立在深入理解的基础上,因为我相信这会带来最好的整体结果,从而产生最好的计划。如果我深入了解某事是如何工作的,那么您可以有效地使用这些技巧和调整,而不是仅仅将它们复制回代码中,所以请不要害怕给我一些更深入的解释并拓宽我的知识。

谢谢你。

4

2 回答 2

72

事件分派线程是由 AWT 管理的特殊线程。基本上,它是一个无限循环运行的线程,处理事件。

java.awt.EventQueue.invokeLaterjavax.swing.SwingUtilities.invokeLater方法是一种提供将在事件队列上运行的代码的方法。编写一个在多线程环境中安全的 UI 框架非常困难,因此 AWT 作者决定只允许在单个特殊线程上对 GUI 对象进行操作。所有事件处理程序都将在此线程上执行,所有修改 GUI 的代码也应在此线程上运行。

现在 AWT 通常不会检查您是否没有从另一个线程发出 GUI 命令(用于 C# 的 WPF 框架会这样做),这意味着可以编写大量代码并且对此几乎不可知并且不会遇到任何问题。但这会导致未定义的行为,因此最好的办法是始终确保 GUI 代码在事件调度线程上运行。invokeLater提供了一种机制来做到这一点。

一个典型的例子是你需要运行一个长时间运行的操作,比如下载一个文件。因此,您启动一​​个线程来执行此操作,然后当它完成时,您可以使用它invokeLater来更新 UI。如果您没有使用invokeLater,而是直接更新了 UI,您可能会遇到竞态条件并且可能会发生未定义的行为。

维基百科有更多信息

此外,如果您想知道为什么 AWT 作者不只是使工具包多线程,这里有一篇好文章。

于 2011-08-27T20:39:35.493 回答
13

EventDispatchThread(EDT) 是仅为 Swing GUI 和 *Swing 的相关事件保留的特殊线程,例如创建/更改/更新Swing JComponents,更多问题请参见此处此处

BackGround Tasks所有从,到 GUI 的输出都Runnable#Thread必须包装到invokeLater()中,从同步对象到invokeAndWait();

于 2011-08-27T20:54:26.800 回答