SwingUtilities.invokeLater()为什么需要它?
为什么有必要在SwingUtilities.invokeLater()
放置GUI更新代码?
为什么不能由Swing自己照顾呢? 为什么调用者不得不关心swing如何处理UI更新?
Swing对象不是线程安全的 。 SwingUtilities.invokeLater()
允许任务在稍后的时间点执行,顾名思义; 但更重要的是,任务将在AWT事件调度线程上执行。 当使用invokeLater
,任务是asynchronous执行的; 还有invokeAndWait
,直到任务完成执行才会返回。
关于不使Swing线程安全的决定的一些信息可以在这里find: multithreading工具包:失败的梦想?
因为GUI更新必须在事件派发线程中完成。 如果你在一个不同的线程中操作,那么在invokeLater
执行更新会将它从你的线程中拉出,并进入事件线程。
更多解释在这里: http : //www.oracle.com/technetwork/java/painting-140037.html
在Swing上进行大规模更新(比如从数据库重新填充JTable)的聪明之处在于获取底层模型,在线程中对模型进行更新,然后使用invokeLater
发出通知。 这让你的GUI响应事件和重绘。 如果更新将会非常广泛,那么甚至可以在更新的同时定期使用invokeLater
来启动这些通知,就像每隔一秒钟或两天一样。
Swing是单线程的。 UI的每一次更新都必须发生在所谓的EDT–即主要的GUI线程Swing(我认为AWT)所使用的event-dispather线程中。 如果你不这样做,那么奇怪的事情可以或将会发生(虽然我喜欢Windows FOrms在这里只是抛出一个exception,如果你做错了)。
这就是说,你不需要把每一个UI操作都包装到SwingUtilities.invokeLater()
– 如果你正在编写的代码已经被EDT执行了,这是不需要的。 所以button点击的ActionListener
不需要这个。 但是一个外部对象的侦听器,在其他线程中运行,在某处更新JLabel
– 在那里你需要它。
Swing不是写成一个线程安全的GUI工具包,所以所有的GUI更新都应该从一个线程发生,以避免任何死锁。 在Swing中,这是事件调度程序线程(EDT)。
有关更多详细信息,请参阅Java教程中的并发Swing 。 它也引用这个博客条目,为什么很难写一个multithreading的GUI工具包。
所有组件的绘画应该在一个单独的线程中执行,所以它们被正确渲染。 这样组件就会知道,哪个部分已经被绘制,哪个部分没有被绘制。
如果在EDT之外调用“绘画”相关方法(paint,update,paintComponent,show,setVisible,pack等),则会尝试绘制两个不同的线程,这可能会带来问题。
当你需要使用另一个线程来更新UI时,你应该用invokeLater工具来调用它,而这个工具反过来会把它放到你的EDT中,所以你仍然在同一个线程中绘制。
你不需要使用它,如果你正在使用已经在EDT中运行的方法进行编码(例如, actionPerformed
或paint
或其中之一),或者如果你正在执行代码而不是UI相关的(例如,处理文件在后台等)
为了更好地理解所有这些概念,请阅读: 单线程规则
SwingUtilities.invokeLater()
导致doRun.run()在AWT事件派发线程上asynchronous执行。 所有待处理的AWT事件处理完成后,都会发生这种情况。 应用程序线程需要更新GUI时应使用此方法。
…
重复其他: Swing不是线程安全的,因此一个线程必须执行所有更新以避免并发问题。 invokeLater是一个在事件处理线程内执行某些东西的实用方法。
为什么Swing不是在内部进行的:这是我的印象…我想是因为这太过分了 – 要检查更新发生的每个地方。 它会膨胀Swing代码,使代码的审查和可维护性变得困难。
另一方面,应用程序不知道它是不是在GUI线程内执行并调用invokeLater并不那么困难。 这将是当自己的应用程序之前启动一些线程。