EventQueue.invokeLater(new Runnable())

起因:什麼是 EventQueue.invokeLater,需要用嗎?
EventQueue.invokeLater(new Runnable(){
public void run(){
try{*/
MyAbout frame =new MyAbout();
frame.setVisible(true);
}catch(Exception e){
e.printStackTrace();
}
}
});
========================================================================
API中:

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)
導致 runnablerun 方法在 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的源代碼

    public static void invokeLater(Runnable runnable) {
        Toolkit.getEventQueue().postEvent(
            new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
    }這裏可以看到,每調用一次,除了外面自己的new Runnable對象以外,裏面還會new 一個InvocationEvent對象,所以一來這裏浪費了大量內存和CPU時間,不停的new出東西來;
而來的確正確的做法應該是搞個後臺線程或者線程池來處理這些事件;

---------------------------------------------------------------------------------------

OK,資料現就這些,大概也瞭解了是怎麼回事,留下備用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章