新聞中心
【獨(dú)家特稿】在基于Java Swing進(jìn)行圖形界面開(kāi)發(fā)的時(shí)候,經(jīng)常遇到的就是Swing多線程問(wèn)題。我們可以想想一下,如果需要在一個(gè)圖形界面上顯示很多數(shù)據(jù),這些數(shù)據(jù)是經(jīng)過(guò)長(zhǎng)時(shí)間、復(fù)雜的查詢和運(yùn)算得到的。如果在圖形界面的同一個(gè)線程中進(jìn)行查詢和運(yùn)算工作則會(huì)導(dǎo)致一段時(shí)間界面處于死機(jī)狀態(tài),這會(huì)給用戶帶來(lái)不良的互動(dòng)感受。為了解決這個(gè)問(wèn)題,一般會(huì)單獨(dú)啟動(dòng)一個(gè)線程進(jìn)行運(yùn)算和查詢工作,并隨時(shí)更新圖形界面。這時(shí)候,另一個(gè)問(wèn)題就出現(xiàn)了,可能不僅沒(méi)有解決原來(lái)偶爾死機(jī)問(wèn)題,還可能導(dǎo)致程序徹底死掉。幸運(yùn)的是在JDK中暗藏了一個(gè)中斷程序的快捷鍵,就是CTRL+BREAK,這個(gè)快捷鍵Sun并沒(méi)有在文檔中公布。如果在命令行模式下啟動(dòng)Java程序,然后按CTRL+BREAK鍵,會(huì)得到堆棧的跟蹤信息。從這些跟蹤信息中就可以知道具體引發(fā)死機(jī)的位置了。

為無(wú)錫等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及無(wú)錫網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、無(wú)錫網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!
當(dāng)一個(gè)程序產(chǎn)生死鎖的時(shí)候,你一定會(huì)希望盡快找到原因并且解決它。這時(shí)候,你一般的精力會(huì)用在查找引發(fā)死鎖的位置,另一半的精力會(huì)用于對(duì)堆棧進(jìn)行跟蹤一確定引發(fā)死鎖的原因。但是在Java Swing程序中,你的所有努力可能都是沒(méi)有價(jià)值的。這是因?yàn)镴ava對(duì)Swing的多線程編程有一個(gè)特殊要求。就是在Swing里,只能在與Swing相同的線程里對(duì)GUI元件進(jìn)行修改。
也就是說(shuō),如果你要執(zhí)行類似于jLabel1.setText("blabla")代碼,必須在Swing線程中,而不允許在其他線程當(dāng)中。如果必須在其他線程中修改元件,可以使用類似一下方式解決:
- SwingUtilities.invokeLater(new Runnable() {
- public void run() {
- jLabel1.setText("blabla");
- }
- }
invokeLater方法雖然表面有時(shí)間延遲執(zhí)行含義,但是實(shí)際上幾乎沒(méi)有任何影響,可能在幾毫秒之內(nèi)就會(huì)被執(zhí)行。另外還有一個(gè)invokeAndWait方法,除非特殊需要,否則幾乎是不用的。
在不使用invokeLater的情況下,導(dǎo)致刷新問(wèn)題是可以理解的,但是導(dǎo)致死鎖就優(yōu)點(diǎn)令人匪夷所思了。幸運(yùn)的是,不是任何時(shí)候都需要調(diào)用改方法,這是因?yàn)榇蠖鄶?shù)情況下,我們都是在與Swing同一個(gè)線程里進(jìn)行界面更新。例如監(jiān)聽(tīng)按鈕點(diǎn)擊事件的ActionListener.actionPerformed方法就是運(yùn)行在與Swing相同的線程中的。但是如果在回調(diào)類中引用了另一個(gè)類,并且是不屬于AWT/Swing的,那么結(jié)果就很難確定了。所以說(shuō)使用invokeLater應(yīng)該是最安全的。
需要注意的是,在invokeLater做的任何事情,都會(huì)導(dǎo)致Swing線程窗口繪制工作暫停下來(lái),等候invokeLater工作結(jié)束。所以不要在invokeLater進(jìn)行耗時(shí)操作,盡量只執(zhí)行那些界面繪制相關(guān)的工作。可以通過(guò)代碼重構(gòu),將那些與界面更新相關(guān)的代碼集中起來(lái)統(tǒng)一處理。
一個(gè)建議是那些在Swing中使用的類進(jìn)行合理的設(shè)計(jì)。代碼執(zhí)行前判斷是否處于Swing線程當(dāng)中(使用SwingUtilities.isEventDispatchThread()方法),如果不是,則需要通過(guò)SwingUtilities.invokeLater(Runnable)執(zhí)行,否則則直接執(zhí)行代碼。但是這說(shuō)起來(lái)簡(jiǎn)單,但是實(shí)際操作會(huì)遇到很多困難。
【編輯推薦】
- 有趣的Java對(duì)象序列化緩存問(wèn)題
- 關(guān)于Java對(duì)象序列化您不知道的5件事
- Java 7 I/O新功能探秘:同步操作,多播與隨機(jī)存取
- Java實(shí)用技巧:當(dāng)不能拋出checked異常時(shí)
- 多線程開(kāi)發(fā)的捷徑:構(gòu)建Java并發(fā)模型框架
當(dāng)前名稱:JavaSwing多線程死鎖問(wèn)題解析
本文地址:http://www.dlmjj.cn/article/djgcdip.html


咨詢
建站咨詢
