程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java Swing多線程死鎖問題解析

Java Swing多線程死鎖問題解析

編輯:關於JAVA

在基於Java Swing進行圖形界面開發的時候,經常遇到的就是Swing多線程問題。我們可以想想一下, 如果需要在一個圖形界面上顯示很多數據,這些數據是經過長時間、復雜的查詢和運算得到的。如果在圖 形界面的同一個線程中進行查詢和運算工作則會導致一段時間界面處於死機狀態,這會給用戶帶來不良的 互動感受。為了解決這個問題,一般會單獨啟動一個線程進行運算和查詢工作,並隨時更新圖形界面。這 時候,另一個問題就出現了,可能不僅沒有解決原來偶爾死機問題,還可能導致程序徹底死掉。幸運的是 在JDK中暗藏了一個中斷程序的快捷鍵,就是CTRL+BREAK,這個快捷鍵Sun並沒有在文檔中公布。如果在命 令行模式下啟動Java程序,然後按CTRL+BREAK鍵,會得到堆棧的跟蹤信息。從這些跟蹤信息中就可以知道 具體引發死機的位置了。

當一個程序產生死鎖的時候,你一定會希望盡快找到原因並且解決它。這時候,你一般的精力會用在 查找引發死鎖的位置,另一半的精力會用於對堆棧進行跟蹤一確定引發死鎖的原因。但是在Java Swing程 序中,你的所有努力可能都是沒有價值的。這是因為Java對Swing的多線程編程有一個特殊要求。就是在 Swing裡,只能在與Swing 相同的線程裡對GUI元件進行修改。

也就是說,如果你要執行類似於jLabel1.setText("blabla")代碼,必須在Swing線程中,而不允許在 其他線程當中。如果必須在其他線程中修改元件,可以使用類似一下方式解決:

SwingUtilities.invokeLater(new Runnable() {
       public void run() {
           jLabel1.setText("blabla");
      }
   }

invokeLater方法雖然表面有時間延遲執行含義,但是實際上幾乎沒有任何影響,可能在幾毫秒之內就 會被執行。另外還有一個invokeAndWait方法,除非特殊需要,否則幾乎是不用的。

在不使用invokeLater的情況下,導致刷新問題是可以理解的,但是導致死鎖就優點令人匪夷所思了。 幸運的是,不是任何時候都需要調用改方法,這是因為大多數情況下,我們都是在與Swing同一個線程裡 進行界面更新。例如監聽按鈕點擊事件的 ActionListener.actionPerformed方法就是運行在與Swing相同 的線程中的。但是如果在回調類中引用了另一個類,並且是不屬於AWT/Swing的,那麼結果就很難確定了 。所以說使用invokeLater應該是最安全的。

需要注意的是,在 invokeLater做的任何事情,都會導致Swing線程窗口繪制工作暫停下來,等候 invokeLater工作結束。所以不要在 invokeLater進行耗時操作,盡量只執行那些界面繪制相關的工作。 可以通過代碼重構,將那些與界面更新相關的代碼集中起來統一處理。

一個建議是那些在Swing中使用的類進行合理的設計。代碼執行前判斷是否處於Swing線程當中(使用 SwingUtilities.isEventDispatchThread()方法),如果不是,則需要通過 SwingUtilities.invokeLater(Runnable)執行,否則則直接執行代碼。但是這說起來簡單,但是實際操作 會遇到很多困難。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved