您好,登錄后才能下訂單哦!
這篇文章主要講解了“編碼Swing多線程的過程中有什么誤區(qū)”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“編碼Swing多線程的過程中有什么誤區(qū)”吧!
1、不要以為Swing是多線程的,實際上Swing的UI是單線程的
2、不要以為SwingUtilities.的兩個invoke是多線程,實際上它還是單線程的
3、不要以為invokeLater的意思是當前線程執(zhí)行完再執(zhí)行目標線程;以為invokeAndWait的意思是等待目標線程執(zhí)行完再執(zhí)行當前線程,實際上壓根就不是那么回事
問題代碼1:大意是在按下某個按鈕的時候調(diào)用一個遠程服務(wù)
1.JButtonbutton=newJButton();
2.button.addActionListener(newActionListener(){
3.@Override
4.publicvoidactionPerformed(ActionEvente){
5.invokeRemoteService();//可能需要等待
6.}
7.});
在swing系統(tǒng)中,有一個頂級的java.awt.Container(可能是一個JFrame或JDialog實例),負責啟動一個EventDispatchThread線程,單線程,這個線程是負責處理UI事件的。
首先,界面Swing控件向EventDispatchThread的EventQueue提交一個event,由EventDispatchThread負責調(diào)度各個event的執(zhí)行。例如,按下一個JButton的時候,JButton向EventQueue執(zhí)行postEvent,提交一個ActionEvent.EventDispatchThread線程根據(jù)調(diào)度算法執(zhí)行到該event的時候,會調(diào)用JButton上的processActionEvent,JButton再調(diào)用actionPerformed,這過程并沒有執(zhí)行任何newThread()。start()代碼,也就是說JButton的ActionListener.actionPerformed()中的代碼完全是在EventDispatchThread線程內(nèi)執(zhí)行的。
所以,假如我們在任何ActionListener、MouseListener等對象中編寫耗時的邏輯,那么整個Swing系統(tǒng)就會出現(xiàn)響應遲鈍的現(xiàn)象,更有甚者,如果在這些Listener中執(zhí)行線程wait(),以等待另一個線程的鎖定資源或計算結(jié)果,那么實際上就是EventDispatchThread線程被阻塞,整個系統(tǒng)界面就會處于無響應狀態(tài),一點反應都沒有。
以上是誤解1造成的,了解這個過程,就很容易看出上面這段代碼的問題是什么原因了。解決的方法也倒比較簡單,直接newThread()。start();就可以保證EventDispatchThread執(zhí)行到當前方法的時候快速返回,以便可以去響應來自用戶界面的其他事件。
Swing多線程編碼過程中的誤區(qū)有哪些
問題代碼2:大意是在按下某個按鈕的時候調(diào)用一個遠程服務(wù),同時處理其他事情
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()完成之前就能夠得到執(zhí)行,所以造成了invokeRemoteService()/doOtherThing()好像是在兩個線程里執(zhí)行的假象。實際上invokeLater是把目標代碼打包成一個Event提交到EventQueue去了,等到EventDispatchThread線程執(zhí)行完當前代碼段的doOtherThing()后,再去執(zhí)行這個EventQueue中的Event,這時候就會執(zhí)行到這個invokeRemoteService()方法。但是,實際上這兩個方法都是在EventDispatchThread中執(zhí)行的,并沒有任何其他Thread來執(zhí)行。于是,問題1的問題還是沒解決。實際上直接newThread()。start()方法就可以了,使用SwingUtilities完全是由于誤解造成的濫用。
測試方法,在位置A和位置B都加上下面這行代碼:
System.out.println(Thread.currentThread()。getId()+Thread.currentThread()。getName());
返回的結(jié)果都是一樣的:
21AWT-EventQueue-0
21AWT-EventQueue-0
一般情況下(除了系統(tǒng)啟動時后臺創(chuàng)建的Daemon線程),系統(tǒng)的所有執(zhí)行功能邏輯和業(yè)務(wù)邏輯的線程都應該是從界面操作觸發(fā)的。我們應該清楚哪些需要或應該放到EventDispatchThread中去執(zhí)行,哪些需要或應該創(chuàng)建一個新線程去執(zhí)行,也需要清醒的知道自己當前編寫的是屬于什么邏輯。
這個問題我覺得應該把代碼分成3層,第一層,UI層,包括UI控件上的Listener邏輯,這是應該給EventDispatchThread去執(zhí)行的,必須簡短高效,快速return;這一層做不完的事情通過newThread()。start()交給下一層去做,我稱之為控制層;然后控制層再去調(diào)用具體的業(yè)務(wù)代碼,即第三層,業(yè)務(wù)層。所有由UI控件觸發(fā)的邏輯都應該這么分。
另一個問題是,Swing并不推薦在EventDispatchThread之外修改界面,那么,如果我們在業(yè)務(wù)層需要repaint某個控件,或者updateUI應該怎么辦呢,那就可以使用SwingUtilities來處理了,這才是正確使用SwingUtilities的場景,也是設(shè)計這個工具的目的。
感謝各位的閱讀,以上就是“編碼Swing多線程的過程中有什么誤區(qū)”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對編碼Swing多線程的過程中有什么誤區(qū)這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。