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

Java 使用EDT调度简单事件的必要性,java,swing,awt,event-dispatch-thread,Java,Swing,Awt,Event Dispatch Thread,在继续讨论基本查询之前,我首先要声明,我完全知道我的问题与AWT/Swing框架的标准不符。我的查询只是作为一种学术经验,不应该(希望)应用于现实世界的应用程序 AWT/Swing框架构建在基于事件的模型之上,该模型使用单个线程来调度事件。所有与AWT/Swing相关的事件都必须在事件调度程序线程(EDT)上处理,程序员已编程的任何自定义事件都必须通过函数invokeAndWait()和invokeLater()排队。虽然此模型确保框架不会遇到任何类型的线程并发性问题,但它给试图围绕它编写代码的

在继续讨论基本查询之前,我首先要声明,我完全知道我的问题与AWT/Swing框架的标准不符。我的查询只是作为一种学术经验,不应该(希望)应用于现实世界的应用程序

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

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

对于更新JLabel这样的简单任务(甚至不是以恒定速率,可能是每秒一次或两次),是否确实需要通过EDT执行它?这可能意味着什么(除了被整个java编程社区所鄙视之外)(我想要一个可靠的暗示列表,而不仅仅是“它可能会导致EDT混乱”)

假设模型中只有一个线程更新GUI(不是EDT),并且更新不频繁,并且只有在原子操作中更新(更新字符串、原始数据等),那么程序运行时可能不会出现由EDT引起的问题(我猜这算是黑客行为?)

作为一个挑战,我想知道是否有人可以通过从另一个线程调度事件来演示违反AWT/Swing模型的代码,从而导致明显和持续的问题(例如,我不必等待2小时GUI闪烁1帧)呢

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

注:我从未见过也没有分析过AWT/Swing框架的源代码,我的所有知识都是基于互联网研究和个人经验。如果上面有任何错误,请随时纠正我。
对于那些仍然对我上面的例子感到震惊的程序员,我已经更新了我的所有项目,使之符合标准(多么痛苦)。

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

在回答您的另一个问题时,对于所有GUI组件,只有一个EDT

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

因此,现在您有了一个竞争条件:如果UI在后台线程中完成HTML视图的计算之前重新绘制标签(在EDT中),它将绘制旧的HTML,并且您的标签看起来不会更新


你可以说,“那么,我就不在我的标签中使用HTML了。”但问题是这样的情况在Swing库中很普遍——到处都有一个强烈的假设,即事件只在EDT上传递,如果不阅读大量Swing源代码,就无法保证不会遇到这样的问题。

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

在回答您的另一个问题时,对于所有GUI组件,只有一个EDT

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

因此,现在您有了一个竞争条件:如果UI在后台线程中完成HTML视图的计算之前重新绘制标签(在EDT中),它将绘制旧的HTML,并且您的标签看起来不会更新

你可以说,“那么,我就不在我的标签中使用HTML了。”但问题是这样的情况在Swing库中很普遍——到处都有一个强烈的假设,即事件只在EDT上传递,而没有读取大量的t