java.awt
類 EventQueue
java.lang.Object
java.awt.EventQueue
-
public class EventQueue
- extends Object
EventQueue
是一個(gè)與平臺(tái)無關(guān)的類,它將來自于底層同位體類和受信任的應(yīng)用程序類的事件列入隊(duì)列。
它封裝了異步事件指派機(jī)制,該機(jī)制從隊(duì)列中提取事件,然后通過對(duì)此 EventQueue 調(diào)用
dispatchEvent(AWTEvent)
方法來指派這些事件(事件作為參數(shù)被指派)。該機(jī)制的特殊行為是與實(shí)現(xiàn)有關(guān)的。指派實(shí)際排入到該隊(duì)列中的事件(注意,正在發(fā)送到
EventQueue 中的事件可以被合并)的唯一要求是:
- 按順序指派。
- 也就是說,不允許同時(shí)從該隊(duì)列中指派多個(gè)事件。
- 指派順序與它們排隊(duì)的順序相同。
- 也就是說,如果
AWTEvent A 比 AWTEvent B 先排入到
EventQueue 中,那么事件 B 不能在事件 A 之前被指派。
一些瀏覽器將不同代碼基中的 applet 分成獨(dú)立的上下文,并在這些上下文之間建立一道道墻。在這樣的場(chǎng)景中,每個(gè)上下文將會(huì)有一個(gè)
EventQueue 。其他瀏覽器將所有的 applet 放入到同一個(gè)上下文中,這意味著所有 applet
只有一個(gè)全局
EventQueue 。該行為是與實(shí)現(xiàn)有關(guān)的。有關(guān)更多信息,請(qǐng)參照瀏覽器的文檔。
invokeLater
public static void invokeLater(Runnable runnable)
- 導(dǎo)致
runnable 的 run 方法在 the system EventQueue 的指派線程中被調(diào)用。 -
- 參數(shù):
runnable - Runnable 對(duì)象,其
run 方法應(yīng)該在 EventQueue 上同步執(zhí)行- 從以下版本開始:
- 1.2
- 另請(qǐng)參見:
invokeAndWait(java.lang.Runnable)
========================================================================
七嘴八舌:
使用該方式的原因是:awt是單線程模式的,所有awt的組件只能在(推薦方式)事件處理線程中訪問,從而保證組件狀態(tài)的可確定性。
---------------------------------------------------------------------------------------
使用eventqueue.invokelater()好處是顯而易見的,這個(gè)方法調(diào)用完畢后,它會(huì)被銷毀,因?yàn)槟涿麅?nèi)部類是作為臨時(shí)變量存在的,給它分配的內(nèi)存在此時(shí)會(huì)被釋放。這個(gè)對(duì)于只需要在一個(gè)地方使用時(shí)可以節(jié)省內(nèi)存,而且這個(gè)類是不可以被其它的方法或類使用的,只能被EventQueue.invokeLater()來使用。但如果你需要一個(gè)在很多地方都能用到的類,而不是只在某一個(gè)類里面或者方法里用的話,定義成匿名內(nèi)部類顯然是不可取的。
是,runnable是跟線程相關(guān)的類。
swingutilities.invokelater()和eventqueue.invokelater(),后者可以不干擾到事件分發(fā)線程.SwingUtilities版只是一個(gè)薄薄的封裝方法,它直接轉(zhuǎn)而調(diào)用
EventQueue.invokeLater。因?yàn)镾wing框架本身經(jīng)常調(diào)用SwingUtilities,使用SwingUtilities可以減少程序引入的類。
-----------------------------------------------------------------------------------------------------------------------------
實(shí)戰(zhàn)JAVA內(nèi)存泄露問題http://www./kf/201109/104277.html
一個(gè)J2EE產(chǎn)品在生產(chǎn)環(huán)境下出現(xiàn)了內(nèi)存泄露
在內(nèi)存比較大的時(shí)候,生成一個(gè)heap
dump,打開來看什么對(duì)象占內(nèi)存最多,發(fā)現(xiàn)下面這個(gè)類的對(duì)象占了大量的內(nèi)存
Java.awt.EventQueueItem
找到代碼里面用到這個(gè)類的地方,發(fā)現(xiàn)有大概如下的代碼
我們實(shí)現(xiàn)的一個(gè)OnProcess函數(shù)里面真正做事件處理;
//
過程好像比較糾結(jié),第三方是個(gè)外國公司,我們公司的這段代碼之前也是老外寫的,我也還沒搞明白為什么通知和處理要分開,直接想辦法做成處理不就可以了么?!
onEventNofity(***)
{
java.awt.EventQueue.invokeLater(new Runnable(){
public void run() {
doProcess();
}
});
}這段代碼肯定是有問題,這個(gè)invokelater里面代碼看進(jìn)去是用新生成的Runnable對(duì)象構(gòu)造了一個(gè)java.awt.event.InvocationEvent對(duì)象,然后會(huì)放到系統(tǒng)有一個(gè)默認(rèn)的java.awt.EventQueue實(shí)現(xiàn)對(duì)象里面,然后讓一個(gè)java.awt.
EventDispatchThread調(diào)度,然后一個(gè)一個(gè)執(zhí)行這里的run方法;
首先相當(dāng)于每次一個(gè)事件過來的時(shí)候就生成一個(gè)Runnable對(duì)象,進(jìn)而生成InvocationEvent對(duì)象,占用了大量的內(nèi)存,
可糾結(jié)的是為啥以前沒問題?而且這個(gè)版本在我們開發(fā)服務(wù)器上跑了幾個(gè)月現(xiàn)在還一直正常;
中間經(jīng)過各個(gè)環(huán)境下的測(cè)試、日志分析、對(duì)比,終于慢慢發(fā)現(xiàn),從對(duì)日志的時(shí)間分析看,現(xiàn)在的事件處理速度,就是doProcess這里太慢了,導(dǎo)致事件處理不過來,然后大量的Runnable和InvocationEvent對(duì)象堆積在java.awt.EventQueue里面,導(dǎo)致了內(nèi)存的泄露;
昨天講了內(nèi)存泄露問題的原因其實(shí)就是在下面這段代碼中無緣無故的搞個(gè)java.awt.invokeLater(New
Runnable()….,
當(dāng)然,作者本來的用意是好的,其實(shí)就是把收到事件和處理事件做異步化處理,本來的目的也是提高性能里的情況是按照第三方的API,OnEventNotify()需要盡快返回,否則會(huì)堵住后面發(fā)過來的事件;
這段代碼的主要兩個(gè)問題:
1.
java.awt.invokeLater里面每次會(huì)新生成一個(gè)java.awt.event.InvocationEvent對(duì)象;
2.這里的Runnable的匿名類,其實(shí)本來完全可以單獨(dú)定義的,現(xiàn)在這個(gè)寫法,相當(dāng)于每次一個(gè)事件過來都new出一個(gè)Runnable的匿名類來。。。白白浪費(fèi)了大量內(nèi)存
導(dǎo)致內(nèi)存泄露的情況就是事件現(xiàn)在較多,doProcess占用時(shí)間太長,導(dǎo)致java.awt.event.InvocationEvent對(duì)象大量堆積;
所以,解決思路其實(shí)比較明確,
1. 要么提高處理速度使得事件不堆積,
2. 要么改成其他異步化的方式,避免每次生成java.awt.event.InvocationEvent對(duì)象
在開發(fā)環(huán)境下連接到對(duì)方QA環(huán)境,使得數(shù)據(jù)量保持一致,重現(xiàn)了內(nèi)存泄露問題后,經(jīng)過分析調(diào)試測(cè)試,下面幾種方案都在開發(fā)環(huán)境下運(yùn)行良好,內(nèi)存保持穩(wěn)定,gc日志和heapdump都很正常,解決了內(nèi)存泄露問題:
1.
修改了兩個(gè)第三方API相關(guān)的配置參數(shù),使得doProcess這里處理速度提高了很多,于是即使在現(xiàn)在的事件數(shù)量下,仍然可以避免事件堆積;
2.
由于事件處理是該模塊的核心,而且凡是程序運(yùn)行的時(shí)候必然會(huì)有事件不停的發(fā)送過來,所以,修改代碼如下
onEventNofity(***)
{
//這里改成啥事也不做
}
然后程序起來的時(shí)候開一個(gè)線程不停的去做doProcess的事情;
由于這里onEventNotify僅僅是起個(gè)通知的作用,真正的事件是放在內(nèi)部的另外一個(gè)隊(duì)列里,所以這樣做是可以的;如果有參數(shù)依賴,那可以在這個(gè)onEventNotify調(diào)用其他線程池的方式去做
------------------------------------------------------------------------------------------
核桃博客說明:
下面是JDK中java.awt.EventQueue.invokeLater的源代碼
public
static void invokeLater(Runnable runnable) {
Toolkit.getEventQueue().postEvent(
new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
}這里可以看到,每調(diào)用一次,除了外面自己的new Runnable對(duì)象以外,里面還會(huì)new
一個(gè)InvocationEvent對(duì)象,所以一來這里浪費(fèi)了大量內(nèi)存和CPU時(shí)間,不停的new出東西來;
而來的確正確的做法應(yīng)該是搞個(gè)后臺(tái)線程或者線程池來處理這些事件;
---------------------------------------------------------------------------------------
OK,資料現(xiàn)就這些,大概也了解了是怎么回事,留下備用
|