为什么有必要将GUI更新代码放在SwingUtilities.invokeLater()
?
为什么Swing本身不能内部照顾它?为什么调用者必须关心swing如何处理UI更新?
答案 0 :(得分:41)
摆动对象are not thread safe。 SwingUtilities.invokeLater()
允许任务在稍后的某个时间点执行,顾名思义;但更重要的是,该任务将在AWT事件派发线程上执行。使用invokeLater
时,任务以异步方式执行;还有invokeAndWait
,在任务完成执行之前不会返回。
有关不使Swing线程安全的决定的一些信息可以在这里找到:Multithreaded toolkits: A failed dream?
答案 1 :(得分:16)
因为GUI更新必须在事件派发线程中完成。如果您在另一个线程中运行,则在invokeLater
中执行更新会将其从您的线程中拉出并进入事件线程。
此处有更多解释:http://www.oracle.com/technetwork/java/painting-140037.html
在Swing上进行大更新(比如从数据库重新填充JTable)这一聪明的事情是获取底层模型,在线程中对模型进行更新,然后使用invokeLater
触发通知。这可以让你的gui响应事件和重绘。如果更新范围非常广泛,您甚至可以在更新时定期使用invokeLater
触发这些通知,例如每两秒钟。
答案 2 :(得分:8)
Swing是单线程的。 UI 的每次更新都必须从所谓的EDT发生 - 事件 - 调度线程是Swing(我认为AWT)使用的主要GUI线程。如果你不这样做,那么可能或将要发生奇怪的事情(虽然我更喜欢Windows FOrms,如果你做错了就会引发异常)。
话虽如此,您不需要将每个UI操作都包装到SwingUtilities.invokeLater()
中 - 如果您编写的代码已经由EDT执行,则不需要。因此,单击按钮的ActionListener
不需要此项。但是一个外部对象的监听器,在其他一些线程中运行,在某处更新JLabel
- 你需要它。
答案 3 :(得分:5)
Swing没有被编写为线程安全的GUI工具包,因此所有GUI更新都应该从单个线程发生,以避免任何死锁。在Swing中,这是事件调度程序线程(EDT)。
有关详细信息,请参阅Java教程中的Concurrent in Swing。它还引用了this博客文章,说明为什么编写多线程GUI工具包很困难。
答案 4 :(得分:3)
所有组件的绘制都应该在一个线程中执行,因此,它们可以正确呈现。这样组件就会知道,哪些部件已经涂漆,哪部分没有涂漆。
如果你在EDT之外调用一个“绘画”相关的方法(paint,update,paintComponent,show,setVisible,pack等),你将试图在两个不同的线程中绘制,这可能会带来问题。 / p>
当你需要使用另一个线程来更新UI时,你应该使用invokeLater工具调用它,而invokeLater工具又将它放在EDT中,所以你仍然在同一个线程中绘制。
如果您使用在EDT中运行的方法进行编码(例如,actionPerformed
或paint
或其中之一),则无需使用它。或者如果您是执行不与UI相关的代码(例如,在后台处理文件等)
为了更好地理解所有这些概念,请阅读:The single thread rule
答案 5 :(得分:2)
导致doRun.run()在AWT事件派发线程上异步执行。这将在处理完所有挂起的AWT事件后发生。当应用程序线程需要更新GUI时,应该使用此方法 ...
答案 6 :(得分:1)
重复其他人:Swing不是线程安全的,因此一个线程必须执行所有更新以避免并发问题。 invokeLater是一个在事件处理线程中执行某些操作的实用工具方法。
为什么Swing不会在内部做到这一点:这是我的印象......我认为因为它会有点过分 - 检查每个发生更新的地方。它会使Swing代码膨胀,使代码的审查和可维护性变得困难。
另一方面,对于应用程序来说,知道它是否在GUI线程内执行并调用invokeLater并不困难。它将在自己的应用程序之前启动一些线程。