java.awt
类 EventQueue
java.lang.Object java.awt.EventQueue
-
public class EventQueue
extends
Object
EventQueue
是一个与平台无关的类,它将来自于底层同位体类和受信任的应用程序类的事件列入队列。
它封装了异步事件指派机制,该机制从队列中提取事件,然后通过对此 EventQueue
调用 dispatchEvent(AWTEvent)
方法来指派这些事件(事件作为参数被指派)。该机制的特殊行为是与实现有关的。指派实际排入到该队列中的事件(注意,正在发送到 EventQueue
中的事件可以被合并)的唯一要求是:
-
按顺序指派。
- 也就是说,不允许同时从该队列中指派多个事件。 指派顺序与它们排队的顺序相同。
-
也就是说,如果
AWTEvent
A 比AWTEvent
B 先排入到EventQueue
中,那么事件 B 不能在事件 A 之前被指派。
一些浏览器将不同代码基中的 applet 分成独立的上下文,并在这些上下文之间建立一道道墙。在这样的场景中,每个上下文将会有一个 EventQueue
。其他浏览器将所有的 applet 放入到同一个上下文中,这意味着所有 applet 只有一个全局 EventQueue
。该行为是与实现有关的。有关更多信息,请参照浏览器的文档。
invokeLater
public static void invokeLater(Runnable runnable)
-
导致
runnable
的run
方法在the system EventQueue
的指派线程中被调用。 -
-
参数:
-
runnable
-Runnable
对象,其run
方法应该在EventQueue
上同步执行
从以下版本开始:
- 1.2 另请参见:
-
invokeAndWait(java.lang.Runnable)
-
七嘴八舌:
使用该方式的原因是:awt是单线程模式的,所有awt的组件只能在(推荐方式)事件处理线程中访问,从而保证组件状态的可确定性。
---------------------------------------------------------------------------------------
使用eventqueue.invokelater()好处是显而易见的,这个方法调用完毕后,它会被销毁,因为匿名内部类是作为临时变量存在的,给它分配的内存在此时会被释放。这个对于只需要在一个地方使用时可以节省内存,而且这个类是不可以被其它的方法或类使用的,只能被EventQueue.invokeLater()来使用。但如果你需要一个在很多地方都能用到的类,而不是只在某一个类里面或者方法里用的话,定义成匿名内部类显然是不可取的。是,runnable是跟线程相关的类。
swingutilities.invokelater()和eventqueue.invokelater(),后者可以不干扰到事件分发线程.SwingUtilities版只是一个薄薄的封装方法,它直接转而调用 EventQueue.invokeLater。因为Swing框架本身经常调用SwingUtilities,使用SwingUtilities可以减少程序引入的类。
-----------------------------------------------------------------------------------------------------------------------------
实战JAVA内存泄露问题http://www.2cto.com/kf/201109/104277.html
一个J2EE产品在生产环境下出现了内存泄露
在内存比较大的时候,生成一个heap dump,打开来看什么对象占内存最多,发现下面这个类的对象占了大量的内存
Java.awt.EventQueueItem
找到代码里面用到这个类的地方,发现有大概如下的代码
我们实现的一个OnProcess函数里面真正做事件处理;
// 过程好像比较纠结,第三方是个外国公司,我们公司的这段代码之前也是老外写的,我也还没搞明白为什么通知和处理要分开,直接想办法做成处理不就可以了么?!
onEventNofity(***)
{
java.awt.EventQueue.invokeLater(new Runnable(){
public void run() {
doProcess();
}
});
}这段代码肯定是有问题,这个invokelater里面代码看进去是用新生成的Runnable对象构造了一个java.awt.event.InvocationEvent对象,然后会放到系统有一个默认的java.awt.EventQueue实现对象里面,然后让一个java.awt. EventDispatchThread调度,然后一个一个执行这里的run方法;
首先相当于每次一个事件过来的时候就生成一个Runnable对象,进而生成InvocationEvent对象,占用了大量的内存,
可纠结的是为啥以前没问题?而且这个版本在我们开发服务器上跑了几个月现在还一直正常;
中间经过各个环境下的测试、日志分析、对比,终于慢慢发现,从对日志的时间分析看,现在的事件处理速度,就是doProcess这里太慢了,导致事件处理不过来,然后大量的Runnable和InvocationEvent对象堆积在java.awt.EventQueue里面,导致了内存的泄露;
昨天讲了内存泄露问题的原因其实就是在下面这段代码中无缘无故的搞个java.awt.invokeLater(New Runnable()….,
当然,作者本来的用意是好的,其实就是把收到事件和处理事件做异步化处理,本来的目的也是提高性能里的情况是按照第三方的API,OnEventNotify()需要尽快返回,否则会堵住后面发过来的事件;
这段代码的主要两个问题:
1. java.awt.invokeLater里面每次会新生成一个java.awt.event.InvocationEvent对象;
2.这里的Runnable的匿名类,其实本来完全可以单独定义的,现在这个写法,相当于每次一个事件过来都new出一个Runnable的匿名类来。。。白白浪费了大量内存
导致内存泄露的情况就是事件现在较多,doProcess占用时间太长,导致java.awt.event.InvocationEvent对象大量堆积;
所以,解决思路其实比较明确,
1. 要么提高处理速度使得事件不堆积,
2. 要么改成其他异步化的方式,避免每次生成java.awt.event.InvocationEvent对象
在开发环境下连接到对方QA环境,使得数据量保持一致,重现了内存泄露问题后,经过分析调试测试,下面几种方案都在开发环境下运行良好,内存保持稳定,gc日志和heapdump都很正常,解决了内存泄露问题:
1. 修改了两个第三方API相关的配置参数,使得doProcess这里处理速度提高了很多,于是即使在现在的事件数量下,仍然可以避免事件堆积;
2. 由于事件处理是该模块的核心,而且凡是程序运行的时候必然会有事件不停的发送过来,所以,修改代码如下
onEventNofity(***)
{
//这里改成啥事也不做
}
然后程序起来的时候开一个线程不停的去做doProcess的事情;
由于这里onEventNotify仅仅是起个通知的作用,真正的事件是放在内部的另外一个队列里,所以这样做是可以的;如果有参数依赖,那可以在这个onEventNotify调用其他线程池的方式去做
------------------------------------------------------------------------------------------
核桃博客说明:
下面是JDK中java.awt.EventQueue.invokeLater的源代码
而来的确正确的做法应该是搞个后台线程或者线程池来处理这些事件;
---------------------------------------------------------------------------------------
OK,资料现就这些,大概也了解了是怎么回事,留下备用