【Swing入門教程】一步一步做Netbeans(5):Swing的線程管理及如何寫健壯的安全的正確的Swing程序

     又過了12點。N天前在china-pub訂的兩本書經過漫長的等待今天終於到手了:《 Core Java, Vol. 2: Advanced Features 》和《 Filthy Rich Clients 》。這年頭,快遞都漲價了速度倒沒見快哪去。最近有點急躁,沒事,每月都有那麼幾天,哦,別誤會,我是說男性生理週期。

     至本教程,我們一直都只是做些界面或組件,沒過多考慮程序結構和邏輯的問題。事先也聲明瞭,只是做界面,不管邏輯。邏輯可以不做,但是程序的結構可不能亂來,這樣會誤人子弟。回到教程4,其中有一部是初始化文件樹,我們把這段放到界面初始化完並顯示後再做,看看效果怎樣;這樣的話得改一下,給JTree聲明瞭DefaultTreeModel,並增加了一個自定義的狀態欄StatusBar(代碼放在後面):

       JTree初始化部分也修改一下:

      initTree()也跟着修改一下,addDir()方法不變:

     我們想讓主界面出來後再初始化文件樹:

     運行後會出現什麼效果呢?預期是界面出現後出現進度條初始化文件樹,完成後進度條隱藏。而實質上是主界面出現後卡了大概3秒鐘後文件樹出現,卻沒發現進度條。剛學Swing時我也是大罵這JProgressBar怎麼不好用啊。要知道這爲什麼,你就需要了解一下Swing的單線程模式了。

     一:EDT

     無論什麼時候,運行一個Swing應用程序都會自動創建三個線程。一是主線程,它運行着應用程序的主方法。二是工具包線程,負責捕獲系統事件,它不會運行應用程序的代碼,捕獲的事件會發送到第三個線程EDT(Event Dispatch Thread,事件派發線程)。

     EDT與Swing的交互算是最密切的了。它負責把事件派發到適當的組件並調用它們的繪製方法,正是由於此,我們纔會看到一個變化着的界面。可以這樣說,AWT和Swing中的任何事情的進行都或多或少和EDT有關。

     單線程,隊列,你有點眉目了嗎。當我們再EDT中執行一個耗時較長的操作時,界面就刷新不過來了,因爲刷新部分還在排隊。我們以上的程序正是由於此而造成卡3秒的。以前看Swing組件的javadoc時都會看到這樣的一句話:Swing 不是線程安全的。有關更多信息,請參閱 Swing's Threading Policy 。那時我還也真是莫名奇妙。

     二:SwingUtilities

     知道問題所在就好辦了,既然耗時操作不能放到EDT中,那就放到一個新的線程中去吧:

      運行時沒出現什麼問題,進度條也能顯示,看似一切都正常。不過它違反了Swing的單線程規則:修改組件的狀態要在EDT中進行。測試時可能沒引起任何問題,但隨時都有可能出現死鎖。這個我是深有體會,自己開發的編輯器邏輯是沒什麼問題,就是跑着跑着就出現一些莫名其妙的異常來,並且根據異常信息看似和自己寫的代碼半毛子的關係都沒有。

      嘗試用Swing的工具類SwingUtilities中的invokeLater(),它可以用於EDT中發佈一個新任務。一般Netbeans自動生成的代碼中都會用該方法初始化Swing組件。把initData()改成這樣:

三:SwingWorker

      SwingUtilities是很有用,不過它要創建不少匿名Runnable類,但要做的事情多且繁瑣時SwingUtilities寫的代碼就難於閱讀和維護了。這時不妨考慮下SwingWorker,這可是Java SE 6中新加的哦。它可以在一個後臺線程中運行一個特定的任務,在EDT上發佈任務進行的中間結果和最終結果,關於SwingWorker的具體用法請查看javadoc吧,我困得不行了。下面給出構造文件樹的SwingWorker的實現:

      要運行它,將NetbeansUI類中的38行改爲:

搞定,哦,還不能收工。附上StatusBar類的代碼:

 

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