在基於Java Swing進行圖形界面開發的時候經常遇到的就是Swing多線程問題我們可以想想一下如果需要在一個圖形界面上顯示很多數據這些數據是經過長時間復雜的查詢和運算得到的如果在圖形界面的同一個線程中進行查詢和運算工作則會導致一段時間界面處於死機狀態這會給用戶帶來不良的互動感受為了解決這個問題一般會單獨啟動一個線程進行運算和查詢工作並隨時更新圖形界面這時候另一個問題就出現了可能不僅沒有解決原來偶爾死機問題還可能導致程序徹底死掉幸運的是在JDK中暗藏了一個中斷程序的快捷鍵就是CTRL+BREAK這個快捷鍵Sun並沒有在文檔中公布如果在命令行模式下啟動Java程序然後按CTRL+BREAK鍵會得到堆棧的跟蹤信息從這些跟蹤信息中就可以知道具體引發死機的位置了
當一個程序產生死鎖的時候你一定會希望盡快找到原因並且解決它這時候你一般的精力會用在查找引發死鎖的位置另一半的精力會用於對堆棧進行跟蹤一確定引發死鎖的原因但是在Java Swing程序中你的所有努力可能都是沒有價值的這是因為Java對Swing的多線程編程有一個特殊要求就是在Swing裡只能在與Swing相同的線程裡對GUI元件進行修改
也就是說如果你要執行類似於jLabelsetText(blabla)代碼必須在Swing線程中而不允許在其他線程當中如果必須在其他線程中修改元件可以使用類似一下方式解決
SwingUtilitiesinvokeLater(new Runnable() {
public void run() {
jLabelsetText(blabla);
}
}
invokeLater方法雖然表面有時間延遲執行含義但是實際上幾乎沒有任何影響可能在幾毫秒之內就會被執行另外還有一個invokeAndWait方法除非特殊需要否則幾乎是不用的
在不使用invokeLater的情況下導致刷新問題是可以理解的但是導致死鎖就優點令人匪夷所思了幸運的是不是任何時候都需要調用改方法這是因為大多數情況下我們都是在與Swing同一個線程裡進行界面更新例如監聽按鈕點擊事件的ActionListeneractionPerformed方法就是運行在與Swing相同的線程中的但是如果在回調類中引用了另一個類並且是不屬於AWT/Swing的那麼結果就很難確定了所以說使用invokeLater應該是最安全的
需要注意的是在invokeLater做的任何事情都會導致Swing線程窗口繪制工作暫停下來等候invokeLater工作結束所以不要在invokeLater進行耗時操作盡量只執行那些界面繪制相關的工作可以通過代碼重構將那些與界面更新相關的代碼集中起來統一處理
一個建議是那些在Swing中使用的類進行合理的設計代碼執行前判斷是否處於Swing線程當中(使用SwingUtilitiesisEventDispatchThread()方法)如果不是則需要通過SwingUtilitiesinvokeLater(Runnable)執行否則則直接執行代碼但是這說起來簡單但是實際操作會遇到很多困難
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27498.html