java - 使用 EDT 调度简单事件的必要性

标签 java swing awt event-dispatch-thread

在继续讨论基本查询之前,我首先要声明,我完全意识到我的问题违反了 AWT/Swing 框架的标准。我的问题仅仅是作为一种学术经验,并且(希望)永远不应该应用于现实世界的应用程序。

AWT/Swing 框架构建在基于事件的模型之上,该模型使用单个线程来分派(dispatch)事件。所有与 AWT/Swing 相关的事件都必须在事件调度程序线程 (EDT) 上进行处理,并且程序员编写的任何自定义事件都必须通过函数 invokeAndWait() 和 invokeLater() 进行排队。虽然这个模型确保框架永远不会遇到任何类型的线程并发问题,但它给试图围绕它编写代码的程序员带来了很大的痛苦(在 stackoverflow 上搜索 Swing 问题......相当多)。

但是...几年前,在我更加熟悉 AWT/Swing 模型和 EDT 之前,我曾经编写过违反许多 Java 标准的代码(这些代码会让任何理性的程序员感到恐惧)。我违反的标准之一是调用通过非 EDT 的线程更新 GUI 的方法。准确地说,这是一个标准的“长”任务,驻留在辅助线程上,该线程定期更新 JLabel 当前进度。现在检查代码我意识到,尽管代码直接违反了标准,但它在 100% 的情况下都能工作。我注意到没有闪烁,没有文本损坏(因为它是 JLabel),没有抛出随机异常,也没有异常的 GUI 行为。当然,我从一个小例子知道,不能简单地判断AWT/Swing标准是过度保护还是不必要的。由此,我的疑问是:

对于像更新 JLabel 这样的简单任务(甚至不是以恒定速率,可能每秒一次或两次),真的有必要通过 EDT 执行它吗?这可能会产生什么影响(除了被整个 java 编程社区鄙视之外)(我想要一份可靠的影响列表,而不仅仅是“它可能会导致 EDT 困惑”)?

假设一种模型,其中只有一个线程更新 GUI(不是 EDT),并且更新不频繁,并且仅在原子操作(更新字符串、原始数据等)中进行更新,程序是否可以自由运行EDT 引起的问题(我猜这算作黑客攻击吗?)。

作为一个挑战,我想知道是否有人可以提出代码,通过从另一个线程分派(dispatch)事件导致明显且恒定的事件来演示违反 AWT/Swing 模型(如 I don't have to wait 2 GUI 闪烁 1 帧的时间)问题?

顺便说一句,这可能是不相关的,但是新的 EDT 线程是否会为新的 JFrame/Window 对象生成,或者它们都在同一个线程上运行吗?我无法想象一个资源密集型多窗口系统全部运行在一个线程上。

注意:我从未见过或分析过AWT/Swing框架的源代码,我的所有知识都是基于互联网研究和个人经验。以上如有错误,欢迎指正。 对于那些仍然对我上面的例子感到震惊的程序员,我已经更新了我的所有项目以符合标准(真是痛苦)。

最佳答案

失败的示例:将 JLabel 设置为右对齐。然后绘图需要两个步骤 - 测量文本,以计算位置,然后绘制它。如果您在绘制时更改文本(例如,由于动画循环),文本似乎会偶尔跳跃。

回答您的另一个问题 - 所有 GUI 组件只有一个 EDT。

“持续且明显”更改的示例:假设 JLabel 具有 HTML 内容。在后台线程中,设置文本并触发重绘后,还会触发 PropertyChange,这会导致 UI 委托(delegate)重新解析 HTML 并将其设置在客户端属性中(在后台工作)线程,尽管 UI 假定它位于 EDT 中,因为它正在接收事件)。

现在你有一个竞争条件:如果 UI 在完成后台线程中的 HTML View 计算之前重新绘制标签(在 EDT 中),它将绘制旧的 HTML,并且你的标签将显示为未更新。

您可以说:“那么,我不会在标签中使用 HTML。”但关键是这样的情况在 Swing 库中很普遍 - 到处都做出了一个强有力的假设,即事件仅在 EDT 上传递,并且在不阅读大量 Swing 源代码的情况下,您不能保证您不会遇到这样的问题。

关于java - 使用 EDT 调度简单事件的必要性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17979519/

相关文章:

java - 自定义 AWT 标题窗口

java - 使用 Java 进行 XML 解析(JAXB 和根元素)

java - 在 Java 中将 JTable 与对象值的 ArrayList 同步

java - 如何设置JSpinner DateEditor的格式?

java - 显示 JDialog 时如何禁用 Mac 的关于/退出菜单项?

java - Mac OS Java 7 JDialog.dispose 内存泄漏

java - 如何声明其位置导致棋盘对象更新棋子并将棋子存储在给定位置的棋子

java - 在 View 持有者中使用if else禁用edittext android

java - 使用静态嵌套类作为泛型参数

class - 在哪里可以找到标准 Java 类的代码?