SwingUtilities.invokeLater()为什么需要它?

时间:2010-08-23 20:45:00

标签: java swing

为什么有必要将GUI更新代码放在SwingUtilities.invokeLater()

为什么Swing本身不能内部照顾它?为什么调用者必须关心swing如何处理UI更新?

7 个答案:

答案 0 :(得分:41)

摆动对象are not thread safeSwingUtilities.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中运行的方法进行编码(例如,actionPerformedpaint或其中之一),则无需使用它。或者如果您是执行不与UI相关的代码(例如,在后台处理文件等)

为了更好地理解所有这些概念,请阅读:The single thread rule

答案 5 :(得分:2)

SwingUtilities.invokeLater()

  

导致doRun.run()在AWT事件派发线程上异步执行。这将在处理完所有挂起的AWT事件后发生。当应用程序线程需要更新GUI时,应该使用此方法   ...

答案 6 :(得分:1)

重复其他人:Swing不是线程安全的,因此一个线程必须执行所有更新以避免并发问题。 invokeLater是一个在事件处理线程中执行某些操作的实用工具方法。

为什么Swing不会在内部做到这一点:这是我的印象......我认为因为它会有点过分 - 检查每个发生更新的地方。它会使Swing代码膨胀,使代码的审查和可维护性变得困难。

另一方面,对于应用程序来说,知道它是否在GUI线程内执行并调用invokeLater并不困难。它将在自己的应用程序之前启动一些线程。