什么是 EventQueue.invokeLater,需要用吗?

时间:2023-01-25 00:15:04
起因:什么是 EventQueue.invokeLater,需要用吗?

在上一节中,给出了一个简单的Java图像文件查看器viewer的源代码,
其中有一段代码为:
EventQueue.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new ImageViewerFrame();
frame.setTitle("ImageViewer");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});


之后,我在网上查找了一些资料,摘要如下(仅供参考):
========================================================================
SWING包的线程问题:
swing包有一个特点,基于线程不安全特性。可以理解为:如果一个函数没有正确return之前,
swing的显示是不会响应的,如果执行时间长,甚至会像死机一样没有响应。原因是该函数和主函数的执行处于同一
线程上,该函数的执行占用了CPU的执行时间片。因此,建议所有需要同步显示结果的同行们用如下格式调用(原理
重新开启一个线程):


API中:
public class java.awt.EventQueue extends java.lang.Object
EventQueue 是一个与平台无关的类,它将来自于底层同位体类和受信任的应用程序类的事件列入队列。
它封装了异步事件指派机制,该机制从队列中提取事件,然后通过对此 EventQueue调用dispatchEvent(AWTEvent) 
方法来指派这些事件(事件作为参数被指派)。该机制的特殊行为是与实现有关的。指派实际排入到该队列中的
事件(注意,正在发送到 EventQueue 中的事件可以被合并)的唯一要求是:按顺序指派。
也就是说,不允许同时从该队列中指派多个事件。
指派顺序与它们排队的顺序相同。
也就是说,如果 AWTEvent A 比 AWTEvent B 先排入到 EventQueue 中,那么事件 B 不能在事件 A 之前被指派。
一些浏览器将不同代码基中的 applet 分成独立的上下文,并在这些上下文之间建立一道道墙。在这样的场景中,
每个上下文将会有一个 EventQueue。其他浏览器将所有的 applet 放入到同一个上下文中,这意味着所有 applet 
只有一个全局 EventQueue。该行为是与实现有关的。有关更多信息,请参照浏览器的文档。


下面是JDK中java.awt.EventQueue.invokeLater的源代码:
public static void invokeLater(Runnable runnable) 
{
    Toolkit.getEventQueue().postEvent(new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
}
========================================================================


使用该方式的原因是:
1)图像文件查看器viewer使用的是Swing组件,而Swing是线程不安全的,是单线程的设计,所以只能从事件派发
线程访问将要在屏幕上绘制的Swing组件,从而保证组件状态的可确定性。
2)使用eventqueue.invokelater()好处是显而易见的,这个方法调用完毕后,它会被销毁,因为匿名内部类是作
为临时变量存在的,给它分配的内存在此时会被释放。这个对于只需要在一个地方使用时可以节省内存,而且这个
类是不可以被其它的方法或类使用的,只能被EventQueue.invokeLater()来使用。但如果你需要一个在很多地方都
能用到的类,而不是只在某一个类里面或者方法里用的话,定义成匿名内部类显然是不可取的。