【发布时间】:2013-08-01 12:25:55
【问题描述】:
在继续讨论基本查询之前,我首先要声明,我完全意识到我的问题违反了 AWT/Swing 框架的标准。我的查询仅作为学术经验,不应该(希望)应用于现实世界的应用程序。
AWT/Swing 框架建立在基于事件的模型之上,该模型使用单个线程来分派事件。所有与 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 引起的问题(我猜这算作 hack?)。
作为一个挑战,我想知道是否有可能任何人都可以通过从另一个线程调度事件来证明违反 AWT/Swing 模型的代码,从而导致明显和持续(因为我不必等待 2 GUI 闪烁 1 帧的时间)问题?
顺便说一句,这可能是无关的,但是否会为新的 JFrame/Window 对象生成一个新的 EDT 线程,或者它们是否都运行在同一个线程上?我无法想象一个资源密集的多窗口系统都运行在一个线程上。
注意:我从来没有看过也没有分析过 AWT/Swing 框架的源代码,我所有的知识都是基于互联网研究和个人经验。以上如有错误,欢迎指正。 对于那些仍然对我上面的例子感到震惊的程序员,我已经更新了我的所有项目以符合标准(真是痛苦)。
【问题讨论】:
-
请注意,在 JavaFX 中,如果您从另一个线程更新标签,则会出现异常。他们没有犯与 Swing 中相同的错误,即仅记录使用单个线程,而是真正强制执行。阅读this question 也可能是个好主意
-
违反线程规则的代码似乎可以正常工作并不罕见。但是你做的地方越多,你在某个地方出现图形错误的可能性就越大。同一个程序在一个系统上看起来可以正常运行,但在另一个系统上或在不同的 jvm 版本上出现错误也是相当典型的。
-
@kiheru 我知道...但不同之处在于代码“实际上可以工作”...该特定程序已分发到大多数主要操作系统(由我...个人程序)并且他们都没有表现出奇怪的行为。 (在 WinXp/7/8、Mac OS X/Arch Linux/Ubuntu 和 Java 6 ~ Java 7 上测试)。我知道让协议失败仍然是不对的,我的问题是在适当的情况下需要协议。
-
@downvoter 请告诉我为什么这是一个糟糕的问题?
-
这个问题相当没用,特别是如果你不断重复轶事“证据”;-) 是的,你可以打破规则,这有多酷......如果你如此热衷找到一个实际的破损,只需阅读一般线程问题并尝试驱动一些 ui 来展示这些问题。即使有可能(不知道),这也是浪费时间——因为重要的是 other 方式:gui 必须像任何其他应用程序一样正确、健壮、可维护。故意实施错误无助于实现这一目标。
标签: java swing awt event-dispatch-thread