为什么Swing线程模型被认为是错误的,应该如何?

时间:2012-11-22 20:40:53

标签: java multithreading swing

我多次听说Java Swing线程模型是错误的。我不完全理解为什么,我知道这个问题与你可以从主UI线程以外的另一个线程中绘制Drawable的事实有关。我知道有像SwingUtilities.invokeAndWaitSwingUtilities.invokeLater这样的实用功能可以让你在Runnable中进行绘制,而后者又由Event Dispatcher线程运行。我猜这种方式可以确保绘画是同步完成的,这不会使缓冲区处于不连续状态。

我的问题是:“好”的UI工具包的行为如何?采用了哪些解决方案?

4 个答案:

答案 0 :(得分:9)

Brian Goetz的Java Concurrency in Practice

9.1为什么GUI是单线程的?

  

...在过去,GUI应用程序是单线程和GUI事件   从“主要事件循环”处理。现代GUI框架使用a   模型只是略有不同:它们创建一个专门的事件   调度线程(EDT)用于处理GUI事件。单线程GUI   框架并不是Java独有的; Qt,NextStep,MacOS Cocoa,X   Windows和许多其他人也是单线程的。这不适合   缺乏尝试;已经有很多尝试编写多线程   GUI框架,但由于种族的持久性问题   条件和僵局,他们最终都到了   单线程事件队列模型,其中专用线程获取   队列中的事件并将它们分派给应用程序定义的事件   处理程序...

答案 1 :(得分:3)

对于SWT:http://book.javanb.com/swt-the-standard-widget-toolkit/ch05lev1sec7.html

  

SWT实现了单线程用户界面模型,通常称为单元线程。在此模型中,只有用户界面线程可以调用用户界面操作。严格执行此规则。如果您尝试从用户界面线程外部访问SWT对象,则会出现SWTException(“无效的线程访问”)。

所以SWT也是单线程的。但它需要额外的步骤来禁止UI线程之外的UI的任何更改。考虑Swing中的替代方案,其中允许从其他地方修改UI,但会产生迟早的意外结果,这会使新手程序员感到困惑,然后他们会以“硬”方式了解Swing是单线程的。

此外,如果您的设计不清楚,您最终可能会遇到您认为自己处于正确线索但实际上并非如此的情况。您也可能无法可靠地判断哪些线程将访问特定的代码段,但是您可能在自己的代码中存在严重的设计问题。

除此之外,我无法想象为什么Swing的线程模型被认为是“错误”的其他原因。

答案 2 :(得分:1)

当前显示技术的实现方式,在屏幕上绘制像素始终是串行的。您需要每秒生成大约30个图像,并逐个绘制它们。

所以这个绘画不需要多线程,因为你仍然需要在后台进行一些同步。这实际上是Swing正在做的事情 - 它使用一个名为Event Dispatch Thread的特殊线程来安排所有更改在下一个图像之前及时发生。

从技术上讲,如果您使用EDT提交更改,则Swing是线程安全的。这就是invokeLater()invokeAndWait()方法的用途。他们向美国东部时间提交修改。

如果您不使用EDT并提交一些长时间运行的更改,例如按下按钮后计算某些值,您可以看到应用程序无响应,而不是重新绘制自身。因为EDT正忙着为你做计算,并且没有时间安排重新绘制和其他事件。

答案 3 :(得分:0)

Swing有一个线程负责基本上让用户与应用程序的图形部分进行交互。如果您只执行快速任务以响应用户启动的事件,您的应用程序将始终响应。

如果从用户启动的事件执行长时间运行的任务,而不使用分离的线程来运行该任务,则可能会出现问题 - 问题是,当任务运行时,应用程序将冻结。没有重新绘制,用户将无法与它进行全部交互,它看起来就像应用程序刚刚锁定它一样。

如果您在分离的线程中运行任务(例如,您正在下载页面并且您想要通知用户下载已完成),那么您无法直接从该任务更新Swing,而是必须使用您在问题中提到的辅助方法之一。

创建这些任务是一个更加劳动密集的过程,以便您的应用程序始终响应 - 但如果您正在运行需要很长时间的事情(下载文件就是一个很好的示例),应用程序将继续即使在执行任务时也能响应,甚至只要任务本身允许,您甚至可以让用户取消任务。您可以使用模式对话框来阻止用户在执行任务时执行任何其他操作(如果您要这样做),或者使用显示旋转轮或类似内容的进度对话框。但我想重要的是不要让用户认为应用程序只是“冻结”了。