隨筆-10  評(píng)論-11  文章-20  trackbacks-0
             在使用SWT構(gòu)建應(yīng)用程序時(shí),理解系統(tǒng)底層讀取和調(diào)度平臺(tái)GUI事件的線程模型是非常重要的,UI線程的實(shí)現(xiàn)方式會(huì)影響到在應(yīng)用程序中使用 Java 線程時(shí)必須遵守的規(guī)則。

           

          本地事件調(diào)度

                  對(duì)于任何的GUI應(yīng)用程序,不管所使用的是哪一種編程語(yǔ)言和UI工具包,背后的運(yùn)行機(jī)制都是操作系統(tǒng)探測(cè)GUI事件并把它們放到應(yīng)用程序的事件隊(duì)列中去。這種機(jī)制在不同的操作系統(tǒng)平臺(tái)中大同小異。當(dāng)用戶點(diǎn)擊鼠標(biāo)、鍵入字符、或者使窗口獲得焦點(diǎn),操作系統(tǒng)就會(huì)生成應(yīng)用程序的GUI事件,例如鼠標(biāo)點(diǎn)擊、鍵盤輸入、或窗口重繪事件。操作系統(tǒng)決定哪一個(gè)窗口和應(yīng)用程序應(yīng)該接收用戶觸發(fā)的每一個(gè)事件并把它放入應(yīng)用程序的事件隊(duì)列中。

           

                  任何基于窗口的GUI應(yīng)用程序的底層實(shí)現(xiàn)結(jié)構(gòu)都是一個(gè)事件循環(huán)(event loop),應(yīng)用程序初始化并運(yùn)行一個(gè)循環(huán)(loop),用于從事件隊(duì)列中讀取GUI事件,并作出相應(yīng)的反應(yīng)。處理事件的工作必須迅速完成,以保證GUI應(yīng)用程序能夠?qū)τ脩糇鞒隹焖俜磻?yīng)。

           

                  UI事件觸發(fā)的耗時(shí)較長(zhǎng)的操作應(yīng)該在一個(gè)單獨(dú)的線程中執(zhí)行,這樣才能讓事件循環(huán)主線程能夠快速返回,獲取應(yīng)用程序事件隊(duì)列中的下一個(gè)事件。但是,在非UI線程中訪問(wèn)圖形界面部件和平臺(tái)API 必須通過(guò)鎖和串行化的機(jī)制(locking and serialization)來(lái)實(shí)現(xiàn)。違反這個(gè)規(guī)則的應(yīng)用程序會(huì)引起系統(tǒng)調(diào)用失敗,更嚴(yán)重的是鎖住整個(gè)GUI系統(tǒng),使GUI失去反應(yīng)。

           

          SWT UI 線程

                  SWT 遵循系統(tǒng)平臺(tái)所直接支持的這種線程模型,應(yīng)用程序在它的主線程中運(yùn)行事件循環(huán)(event loop),并在主線程中直接調(diào)度線程。UI線程就是Display 對(duì)象被創(chuàng)建的線程,所有其他的圖形部件都必須在這個(gè)UI線程中創(chuàng)建。

                  既然所有的處理事件的代碼是在應(yīng)用程序的UI線程中觸發(fā)的,那么處理事件的程序代碼就能夠不需要任何特殊方法自由訪問(wèn)和調(diào)用圖形部件。不過(guò),在處理長(zhǎng)耗時(shí)的事件操作時(shí),需要使用多線程來(lái)實(shí)現(xiàn)應(yīng)用程序的功能。

           

          注:在非UI線程中調(diào)用任何必須在UI線程調(diào)用的程序,SWT將會(huì)觸發(fā)一個(gè) SWTException 異常。

           

          SWT 應(yīng)用程序的主線程,包括事件循環(huán),其代碼結(jié)構(gòu)如下:

          Java代碼 復(fù)制代碼 收藏代碼
          1. public static void main (String [] args) {   
          2.    Display display = new Display ();   
          3.    Shell shell = new Shell (display);   
          4.    shell.open ();   
          5.    // start the event loop. We stop when the user has done   
          6.    // something to dispose our window.   
          7.    while (!shell.isDisposed ()) {   
          8.       if (!display.readAndDispatch ())   
          9.          display.sleep ();   
          10.    }   
          11.    display.dispose ();   
          12. }  

                  創(chuàng)建圖形部件和打開(kāi)shell 窗口之后,程序讀取和分發(fā)來(lái)自操作系統(tǒng)事件隊(duì)列的事件,直到shell 窗口被銷毀。如果在隊(duì)列中不存在有效事件,display 進(jìn)入睡眠狀態(tài),把運(yùn)行機(jī)會(huì)交給其他程序。

           

                  SWT 提供了在后臺(tái)主線程中調(diào)用圖形部件代碼的訪問(wèn)方法。

           

          運(yùn)行非UI線程

                   在非UI 線程中不能直接調(diào)用UI 代碼,必須提供一個(gè) Runnable對(duì)象,在Runable中調(diào)用UI代碼。Display 類中的syncExec(Runnable) 和 asyncExec(Runnable) 方法用于在事件循環(huán)運(yùn)行期間,在UI 線程中運(yùn)行這些Runnable對(duì)象。

          • syncExec(Runnable)  當(dāng)非UI 線程中的程序代碼依賴于UI 代碼的返回值,或者為了確保在返回到主線程之前Runnable 必須執(zhí)行完成時(shí),應(yīng)該使用這個(gè)方法。SWT 將會(huì)阻塞調(diào)用線程,直到在應(yīng)用程序的UI 線程中運(yùn)行的這個(gè)Runnable運(yùn)行結(jié)束為止。例如,一個(gè)后臺(tái)線程需要基于一個(gè)窗口的當(dāng)前尺寸進(jìn)行某種計(jì)算,就會(huì)需要同步地運(yùn)行獲取窗口尺寸的代碼,然后繼續(xù)其后面的計(jì)算。
          • asyncExec(Runnable)  當(dāng)程序需要執(zhí)行一些UI 操作,但在繼續(xù)執(zhí)行之前不依賴這些操作必須完成的時(shí)候,應(yīng)該使用這個(gè)方法。例如,后臺(tái)主線程更新進(jìn)度條,或者重繪一個(gè)窗口,它可以異步地發(fā)出更新或重繪的請(qǐng)求,并接著繼續(xù)后面的處理,在這種情況下,后臺(tái)主線線程的運(yùn)行時(shí)間和Runnable的運(yùn)行沒(méi)有必然的關(guān)系。
          下面的代碼片段演示了使用這兩個(gè)方法的方式:
          Java代碼 復(fù)制代碼 收藏代碼
          1. // do time-intensive computations   
          2. ...   
          3. // now update the UI. We don't depend on the result,   
          4. // so use async.   
          5. display.asyncExec (new Runnable () {   
          6.    public void run () {   
          7.       if (!myWindow.isDisposed())   
          8.          myWindow.redraw ();   
          9.    }   
          10. });   
          11. // now do more computations   
          12. ...  
                  在使用asyncExec 的時(shí)候,在runnable 中檢查圖形部件是否被銷毀是一個(gè)好的習(xí)慣做法,在調(diào)用asyncExec和Runnable執(zhí)行期間主線程中有可能會(huì)發(fā)生其他的事情,不能保證runnable執(zhí)行時(shí)圖形部件當(dāng)前處于什么狀態(tài)。

          工作臺(tái)(Workbench)和多線程

                  實(shí)現(xiàn)SWT應(yīng)用程序的多線程規(guī)則非常明確,你可以控制事件循環(huán)的初始化,在應(yīng)用程序中使用多線程解決復(fù)雜問(wèn)題。

           

                  向工作臺(tái)添加插件時(shí)的工作機(jī)制要父子一些,下面是使用平臺(tái)(workbench platform)UI 類的一些“規(guī)約”(Rules of engagement),隨著eclipse 的不斷發(fā)布,可能會(huì)出現(xiàn)一些例外:

          • 通常,任何添加到平臺(tái)中的工作臺(tái)(workbench) UI 擴(kuò)展都是在工作臺(tái)的UI 主線程中執(zhí)行的,除非是明確地把它們添加線程中或者是后臺(tái)作業(yè)(background job)中,例如后臺(tái)作業(yè)進(jìn)度條。
          • 如果從工作臺(tái)接收到一個(gè)事件,不能保證它是在UI線程中執(zhí)行的,查閱定義了監(jiān)聽(tīng)器或事件的類的java文檔,如果沒(méi)有特別說(shuō)明使用線程,這個(gè)類就是一個(gè)UI 相關(guān)類,可以在工作臺(tái)主線程中獲得和運(yùn)行。
          • 同樣,除非是文檔明確說(shuō)明,平臺(tái)UI庫(kù)不能視作是線程安全的。請(qǐng)注意,大部分平臺(tái)UI類是在觸發(fā)事件的調(diào)用線程中運(yùn)行監(jiān)聽(tīng)器的,平臺(tái)和JFace API調(diào)用并不檢查是在UI 線程中執(zhí)行的,這意味著如果在非UI 線程中調(diào)用一個(gè)能夠觸發(fā)事件的方法,可能會(huì)引入問(wèn)題。從非UI 線程中調(diào)用SWT的API,SWT會(huì)拋出 SWTException 異常。通常,除非文檔中明確規(guī)定,避免在別的線程中調(diào)用平臺(tái)UI 代碼。
          • 如果你的插件使用多線程或工作臺(tái)作業(yè)(workbench job),必須使用 Display 類的asyncExec(Runnable) 或 syncExec(Runnable) 方法,類調(diào)用任何的工作臺(tái)(workbench)、JFace或SWT 的應(yīng)用程序接口(API),除非是API明確說(shuō)明是可以直接調(diào)用的。
          • 如果在插件中使用 JFace的IRunnableContext 接口 調(diào)用進(jìn)度監(jiān)視器(progress monitor),以運(yùn)行一個(gè)操作,IRunnableContext 提供了一個(gè)參數(shù)來(lái)確定是不是在一個(gè)新的線程中運(yùn)行操作。
          附:
          參考:http://help.eclipse.org/helios/index.jsp?topic=/org.eclipse.platform.doc.isv/guide/swt_threading.htm
          posted on 2011-04-17 21:58 Soap MacTavish 閱讀(1490) 評(píng)論(0)  編輯  收藏

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          <2011年4月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          1234567

          常用鏈接

          留言簿

          隨筆檔案

          文章檔案

          相冊(cè)

          天才輪滑女孩陳晨

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 黎城县| 东港市| 天津市| 乐陵市| 云梦县| 尉犁县| 随州市| 潮安县| 临漳县| 蓬莱市| 仙居县| 平遥县| 武义县| 和平区| 兰溪市| 藁城市| 呼和浩特市| 青浦区| 连云港市| 孙吴县| 乃东县| 渑池县| 东辽县| 军事| 佛教| 宁陵县| 黔东| 富顺县| 河津市| 建阳市| 康马县| 井陉县| 垦利县| 湘阴县| 台中市| 翁牛特旗| 韶关市| 叙永县| 梁平县| 新丰县| 翁源县|