SwingWorker()構(gòu)造器的線程
演示程序用SwingWorker()構(gòu)造器在后臺(tái)執(zhí)行費(fèi)時(shí)的操作,然后更新UI。
這個(gè)演示程序所用的SwingWorker是基于《使用SwingWorker線程》文中提出的SwingWorker類,但重新實(shí)現(xiàn)了它以修正一處競(jìng)態(tài)條件,添加超時(shí)支持,和改進(jìn)了異常處理。
這個(gè)新的實(shí)現(xiàn)還基于DougLea的util.concurrent包的FutureResult類(參見“參考資料”一節(jié))。由于大量依賴了FutureResult所做的工作,SwingWorker類的實(shí)現(xiàn)是簡(jiǎn)單而靈活的。
本節(jié)的余下部分更詳細(xì)地描述了實(shí)現(xiàn)的細(xì)節(jié),請(qǐng)繼續(xù)往下看或直接跳到后面下載源碼。
RunnableFutureResult
FutureResult,正如它的名字所暗示的,它是用來(lái)保持某動(dòng)作的結(jié)果的。它被設(shè)計(jì)成和一個(gè)Callable共同使用,Callable是一個(gè)會(huì)返回結(jié)果的runnable動(dòng)作:
- publicinterfaceCallable{
- Objectcall()throwsException;
- }
新的SwingWorker是一個(gè)RunnableFutureResult。在運(yùn)行時(shí),它把結(jié)果設(shè)成construct()的返回值,然后在事件派發(fā)線程中調(diào)用finished()方法。(注意:SwingWorker是一個(gè)抽象類;你要子類化它并實(shí)現(xiàn)construct()和finished()。)
下面的代碼來(lái)自SwingWorker的run()方法:
- Callablefunction=newCallable(){
- publicObjectcall()throwsException{
- returnconstruct();
- }
- };
- RunnabledoFinished=newRunnable(){
- publicvoidrun(){
- finished();
- }
- };
- setter(function).run();
- SwingUtilities.invokeLater(doFinished);
***段把construct()轉(zhuǎn)換成一個(gè)Callable動(dòng)作,第二段把finished()轉(zhuǎn)換成作為Runnable的doFinished。然后setter(function)被運(yùn)行,doFinished被調(diào)用。
setter(function)
上面缺少的部分是setter(function)。它創(chuàng)建一個(gè)刻板的Runnable。在運(yùn)行時(shí),這個(gè)Runnable調(diào)用參數(shù)指定的function,然后給結(jié)果設(shè)置返回值。下面是來(lái)自FutureResult的代碼:
- publicRunnablesetter(finalCallablefunction){
- returnnewRunnable(){
- publicvoidrun(){
- try{
- set(function.call());
- }
- catch(Throwableex){
- setException(ex);
- }
- }
- };
- }
注意try-catch塊所作的防護(hù)。如果construct()拋出任何東西(Exception、Error等等),都會(huì)被捕捉并記錄下來(lái)。
不要搶跑:先construct,再start
調(diào)用start()來(lái)啟動(dòng)worker線程。這是修訂版的SwingWorker和原來(lái)版本的一個(gè)重要區(qū)別。
在原來(lái)的版本中,SwingWorker()構(gòu)造器自動(dòng)啟動(dòng)線程,這種做法帶來(lái)了一個(gè)線程和子類構(gòu)造器競(jìng)爭(zhēng)的危險(xiǎn):當(dāng)SwingWorker()構(gòu)造器已啟動(dòng)了線程,而子類的構(gòu)造器還沒完成。彌補(bǔ)方法是,先構(gòu)造SwingWorker,然后再調(diào)用start()。
順便一提,RemoteTable并不調(diào)用start()。正確來(lái)說(shuō),SwingWorker是作為一個(gè)Runnable被QueuedExecutor執(zhí)行的。
【編輯推薦】