現在的位置: 首頁 > 編程語言 > 正文

Swing多線程編碼過程中的誤區有哪些

2020年06月05日 編程語言 ⁄ 共 2761字 ⁄ 字型大小 評論關閉

  多學JAVA程序員都是從Swing開始的,但很多人對AWTGUI線程的機制並沒有太深的了解,或者說一直都只了解線程的概念,而不了解AWT對線程的使用。下面學步園小編來講解下Swing多線程編碼過程中的誤區有哪些?

  Swing多線程編碼過程中的誤區有哪些

  1、不要以為Swing是多線程的,實際上Swing的UI是單線程的

  2、不要以為SwingUtilities.的兩個invoke是多線程,實際上它還是單線程的

  3、不要以為invokeLater的意思是當前線程執行完再執行目標線程;以為invokeAndWait的意思是等待目標線程執行完再執行當前線程,實際上壓根就不是那麼回事

  問題代碼1:大意是在按下某個按鈕的時候調用一個遠程服務

  1.JButtonbutton=newJButton();

  2.button.addActionListener(newActionListener(){

  3.@Override

  4.publicvoidactionPerformed(ActionEvente){

  5.invokeRemoteService();//可能需要等待

  6.}

  7.});

  在swing系統中,有一個頂級的java.awt.Container(可能是一個JFrame或JDialog實例),負責啟動一個EventDispatchThread線程,單線程,這個線程是負責處理UI事件的。

  首先,界面Swing控制項向EventDispatchThread的EventQueue提交一個event,由EventDispatchThread負責調度各個event的執行。例如,按下一個JButton的時候,JButton向EventQueue執行postEvent,提交一個ActionEvent.EventDispatchThread線程根據調度演算法執行到該event的時候,會調用JButton上的processActionEvent,JButton再調用actionPerformed,這過程並沒有執行任何newThread()。start()代碼,也就是說JButton的ActionListener.actionPerformed()中的代碼完全是在EventDispatchThread線程內執行的。

  所以,假如我們在任何ActionListener、MouseListener等對象中編寫耗時的邏輯,那麼整個Swing系統就會出現響應遲鈍的現象,更有甚者,如果在這些Listener中執行線程wait(),以等待另一個線程的鎖定資源或計算結果,那麼實際上就是EventDispatchThread線程被阻塞,整個系統界面就會處於無響應狀態,一點反應都沒有。

  以上是誤解1造成的,了解這個過程,就很容易看出上面這段代碼的問題是什麼原因了。解決的方法也倒比較簡單,直接newThread()。start();就可以保證EventDispatchThread執行到當前方法的時候快速返回,以便可以去響應來自用戶界面的其他事件。

  Swing多線程編碼過程中的誤區有哪些

  問題代碼2:大意是在按下某個按鈕的時候調用一個遠程服務,同時處理其他事情

  1.JButtonbutton=newJButton();

  2.button.addActionListener(newActionListener(){

  3.@Override

  4.publicvoidactionPerformed(ActionEvente){

  5.//位置A

  6.SwingUtilities.invokeLater(newRunnable(){

  7.publicvoidrun(){

  8.//位置B

  9.invokeRemoteService();//可能需要等待

  10.}

  11.});

  12.doOtherThing();

  13.}

  14.});

  這段代碼跟第一段代碼唯一的差別是doOtherThing()在invokeRemoteService()完成之前就能夠得到執行,所以造成了invokeRemoteService()/doOtherThing()好像是在兩個線程里執行的假象。實際上invokeLater是把目標代碼打包成一個Event提交到EventQueue去了,等到EventDispatchThread線程執行完當前代碼段的doOtherThing()後,再去執行這個EventQueue中的Event,這時候就會執行到這個invokeRemoteService()方法。但是,實際上這兩個方法都是在EventDispatchThread中執行的,並沒有任何其他Thread來執行。於是,問題1的問題還是沒解決。實際上直接newThread()。start()方法就可以了,使用SwingUtilities完全是由於誤解造成的濫用。

  測試方法,在位置A和位置B都加上下面這行代碼:

  System.out.println(Thread.currentThread()。getId()+Thread.currentThread()。getName());

  返回的結果都是一樣的:

  21AWT-EventQueue-0

  21AWT-EventQueue-0

  一般情況下(除了系統啟動時後台創建的Daemon線程),系統的所有執行功能邏輯和業務邏輯的線程都應該是從界面操作觸發的。我們應該清楚哪些需要或應該放到EventDispatchThread中去執行,哪些需要或應該創建一個新線程去執行,也需要清醒的知道自己當前編寫的是屬於什麼邏輯。

  這個問題我覺得應該把代碼分成3層,第一層,UI層,包括UI控制項上的Listener邏輯,這是應該給EventDispatchThread去執行的,必須簡短高效,快速return;這一層做不完的事情通過newThread()。start()交給下一層去做,我稱之為控制層;然後控制層再去調用具體的業務代碼,即第三層,業務層。所有由UI控制項觸發的邏輯都應該這麼分。

  另一個問題是,Swing並不推薦在EventDispatchThread之外修改界面,那麼,如果我們在業務層需要repaint某個控制項,或者updateUI應該怎麼辦呢,那就可以使用SwingUtilities來處理了,這才是正確使用SwingUtilities的場景,也是設計這個工具的目的。

  以上就是關於「Swing多線程編碼過程中的誤區有哪些」的內容,希望對大家有用。更多資訊請關注學步園。學步園,您學習IT技術的優質平台!

抱歉!評論已關閉.