自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Swing多線程編碼過(guò)程中的誤區(qū)

開發(fā) 后端
很多學(xué)JAVA程序員都是從Swing開始的,但很多人對(duì)AWT GUI線程的機(jī)制并沒(méi)有太深的了解,或者說(shuō)一直都只了解線程的概念,而不了解AWT對(duì)線程的使用。我發(fā)現(xiàn)很多人碰到線程阻塞的問(wèn)題,就通過(guò)調(diào)用 SwingUtilities.invokeLater()來(lái)解決。

很多學(xué)JAVA程序員都是從Swing開始的,但很多人對(duì)AWT GUI線程的機(jī)制并沒(méi)有太深的了解,或者說(shuō)一直都只了解線程的概念,而不了解AWT對(duì)線程的使用。我發(fā)現(xiàn)很多人碰到線程阻塞的問(wèn)題,就通過(guò)調(diào)用 SwingUtilities.invokeLater()來(lái)解決。

其實(shí)這是很容易造成誤會(huì)的地方:

  1. 不要以為Swing 是多線程的,實(shí)際上Swing 的UI是單線程的
  2. 不要以為SwingUtilities.的兩個(gè)invoke是多線程,實(shí)際上它還是單線程的
  3. 不要以為invokeLater的意思是當(dāng)前線程執(zhí)行完再執(zhí)行目標(biāo)線程;以為invokeAndWait的意思是等待目標(biāo)線程執(zhí)行完再執(zhí)行當(dāng)前線程,實(shí)際上壓根就不是那么回事

問(wèn)題代碼1:大意是在按下某個(gè)按鈕的時(shí)候調(diào)用一個(gè)遠(yuǎn)程服務(wù)

  1. JButton button = new JButton();   
  2. button.addActionListener(new ActionListener(){   
  3. @Override   
  4. public void actionPerformed(ActionEvent e) {   
  5. invokeRemoteService();//可能需要等待   
  6. }   
  7. });  

在swing系統(tǒng)中,有一個(gè)頂級(jí)的java.awt.Container(可能是一個(gè)JFrame或JDialog實(shí)例),負(fù)責(zé)啟動(dòng)一個(gè)EventDispatchThread線程,單線程,這個(gè)線程是負(fù)責(zé)處理UI事件的。

首先,界面Swing控件向EventDispatchThread的EventQueue提交一個(gè)event,由 EventDispatchThread負(fù)責(zé)調(diào)度各個(gè)event的執(zhí)行。例如,按下一個(gè)JButton的時(shí)候,JButton向EventQueue執(zhí)行 postEvent,提交一個(gè)ActionEvent。EventDispatchThread線程根據(jù)調(diào)度算法執(zhí)行到該event的時(shí)候,會(huì)調(diào)用 JButton上的processActionEvent,JButton再調(diào)用actionPerformed,這過(guò)程并沒(méi)有執(zhí)行任何new Thread().start()代碼,也就是說(shuō)JButton的ActionListener.actionPerformed()中的代碼完全是在 EventDispatchThread線程內(nèi)執(zhí)行的。

所以,假如我們?cè)谌魏蜛ctionListener、MouseListener等對(duì)象中編寫耗時(shí)的邏輯,那么整個(gè)Swing系統(tǒng)就會(huì)出現(xiàn)響應(yīng)遲鈍的現(xiàn)象,更有甚者,如果在這些Listener中執(zhí)行線程wait(),以等待另一個(gè)線程的鎖定資源或計(jì)算結(jié)果,那么實(shí)際上就是 EventDispatchThread線程被阻塞,整個(gè)系統(tǒng)界面就會(huì)處于無(wú)響應(yīng)狀態(tài),一點(diǎn)反應(yīng)都沒(méi)有。

以上是誤解1造成的,了解這個(gè)過(guò)程,就很容易看出上面這段代碼的問(wèn)題是什么原因了。解決的方法也倒比較簡(jiǎn)單,直接new Thread().start();就可以保證EventDispatchThread執(zhí)行到當(dāng)前方法的時(shí)候快速返回,以便可以去響應(yīng)來(lái)自用戶界面的其他事件。

問(wèn)題代碼2:大意是在按下某個(gè)按鈕的時(shí)候調(diào)用一個(gè)遠(yuǎn)程服務(wù),同時(shí)處理其他事情

  1. JButton button = new JButton();   
  2. button.addActionListener(new ActionListener(){   
  3. @Override   
  4. public void actionPerformed(ActionEvent e) {   
  5. //位置A   
  6. SwingUtilities.invokeLater(new Runnable() {   
  7.      public void run() {   
  8. //位置B   
  9.          invokeRemoteService();//可能需要等待   
  10.      }   
  11. });   
  12. doOtherThing();   
  13. }   
  14. });  

這段代碼跟第一段代碼唯一的差別是doOtherThing()在invokeRemoteService ()完成之前就能夠得到執(zhí)行,所以造成了invokeRemoteService ()/doOtherThing()好像是在兩個(gè)線程里執(zhí)行的假象。實(shí)際上invokeLater是把目標(biāo)代碼打包成一個(gè)Event提交到 EventQueue去了,等到EventDispatchThread線程執(zhí)行完當(dāng)前代碼段的doOtherThing()后,再去執(zhí)行這個(gè) EventQueue中的Event,這時(shí)候就會(huì)執(zhí)行到這個(gè)invokeRemoteService ()方法。但是,實(shí)際上這兩個(gè)方法都是在EventDispatchThread中執(zhí)行的,并沒(méi)有任何其他Thread來(lái)執(zhí)行。于是,問(wèn)題1的問(wèn)題還是沒(méi)解決。實(shí)際上直接new Thread().start()方法就可以了,使用SwingUtilities完全是由于誤解造成的濫用。

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

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

返回的結(jié)果都是一樣的:

21AWT-EventQueue-0

21AWT-EventQueue-0 

[討論]

一般情況下(除了系統(tǒng)啟動(dòng)時(shí)后臺(tái)創(chuàng)建的Daemon線程),系統(tǒng)的所有執(zhí)行功能邏輯和業(yè)務(wù)邏輯的線程都應(yīng)該是從界面操作觸發(fā)的。我們應(yīng)該清楚哪些需要或應(yīng)該放到EventDispatchThread中去執(zhí)行,哪些需要或應(yīng)該創(chuàng)建一個(gè)新線程去執(zhí)行,也需要清醒的知道自己當(dāng)前編寫的是屬于什么邏輯。

這個(gè)問(wèn)題我覺(jué)得應(yīng)該把代碼分成3層,第一層,UI層,包括UI控件上的Listener邏輯,這是應(yīng)該給EventDispatchThread 去執(zhí)行的,必須簡(jiǎn)短高效,快速return;這一層做不完的事情通過(guò)new Thread().start()交給下一層去做,我稱之為控制層;然后控制層再去調(diào)用具體的業(yè)務(wù)代碼,即第三層,業(yè)務(wù)層。所有由UI控件觸發(fā)的邏輯都應(yīng)該這么分。

另一個(gè)問(wèn)題是,Swing并不推薦在EventDispatchThread之外修改界面,那么,如果我們?cè)跇I(yè)務(wù)層需要repaint某個(gè)控件,或者updateUI應(yīng)該怎么辦呢,那就可以使用SwingUtilities來(lái)處理了,這才是正確使用SwingUtilities的場(chǎng)景,也是設(shè)計(jì)這個(gè)工具的目的。

原文鏈接:http://seaman.iteye.com/blog/608584

【編輯推薦】

  1. 控件位置可以配置的Swing桌面
  2. Swing特效:漸顯效果
  3. 簡(jiǎn)述Java圖形用戶界面設(shè)計(jì)(Swing)
  4. 用Swing制作精美的圖層疊加圖
  5. 簡(jiǎn)述Java圖形用戶界面設(shè)計(jì)(Swing)
責(zé)任編輯:林師授 來(lái)源: seaman的博客
相關(guān)推薦

2011-05-03 10:31:59

噴墨打印機(jī)注墨誤區(qū)

2010-09-13 10:00:51

CSS注釋

2012-06-14 08:46:03

IDC云計(jì)算

2009-05-15 09:33:52

開發(fā)線程沖突lock

2009-07-16 08:53:03

Swing任務(wù)Swing線程

2009-07-16 09:54:44

LookupEventSwing線程

2010-05-24 14:04:48

JavaSwing多線程

2009-07-14 15:34:22

Swing中的線程GUI程序

2009-04-30 09:10:42

JavaSwing線程安全

2009-07-16 09:28:37

軟件開發(fā)過(guò)程

2022-09-06 08:25:13

線程異步任務(wù)

2013-08-15 12:26:40

阿里云飛天

2010-07-01 14:05:43

SNMPMIB

2011-04-11 17:28:50

oracle存儲(chǔ)select語(yǔ)句

2009-07-23 14:10:38

Hibernate J

2022-03-07 07:57:04

Linux工具內(nèi)存

2010-03-04 09:54:24

Android開發(fā)

2010-11-11 09:40:34

BUG

2016-09-07 20:28:17

MySQL存儲(chǔ)數(shù)據(jù)庫(kù)

2024-01-15 00:25:59

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)