涂焱楚
摘 要 SwingWorker類是Java語(yǔ)言JDK中Swing包的一個(gè)類,主要用來(lái)在GUI程序中實(shí)現(xiàn)耗時(shí)的工作任務(wù)線程。但我們?cè)诜荊UI程序的普通程序中也可使用來(lái)實(shí)現(xiàn)普通多線程程序,簡(jiǎn)單方便功能更強(qiáng)。
關(guān)鍵詞 SwingWorker;多線程;Java
引言
在計(jì)算機(jī)系統(tǒng)中,進(jìn)程是指程序的一次動(dòng)態(tài)執(zhí)行過(guò)程。程序是指令、數(shù)據(jù)及其組織形式的描述,進(jìn)程則是程序運(yùn)行時(shí)的實(shí)體,也是操作系統(tǒng)進(jìn)行資源分配的基本單位。多進(jìn)程操作系統(tǒng)支持多個(gè)進(jìn)程的同時(shí)運(yùn)行。線程是比進(jìn)程更小的執(zhí)行單位,是進(jìn)程的基礎(chǔ)之上進(jìn)一步的劃分,是進(jìn)程中執(zhí)行運(yùn)算的最小單位,亦是操作系統(tǒng)調(diào)度運(yùn)行的基本單位。線程和進(jìn)程一樣,也是實(shí)現(xiàn)并發(fā)的一個(gè)基本單位。所謂多線程是指一個(gè)進(jìn)程在執(zhí)行過(guò)程中可以產(chǎn)生多個(gè)更小的程序單元,也即是線程,這些線程同時(shí)存在,同時(shí)運(yùn)行。可以說(shuō),多線程在較低的層次上擴(kuò)展了多任務(wù)的概念,但是與進(jìn)程相比較,線程更輕量級(jí),創(chuàng)建、撤銷一個(gè)線程比啟動(dòng)一個(gè)新進(jìn)程的開(kāi)銷要小得多。進(jìn)程和線程在現(xiàn)在的主流操作系統(tǒng)中都得到了較好的支持。在實(shí)際應(yīng)用中,多線程非常有用,Java語(yǔ)言很早就對(duì)多線程程序的開(kāi)發(fā)提供支持。
1 在Java中使用多線程的一般方式
Java語(yǔ)言中很早就實(shí)現(xiàn)了對(duì)多線程編程的支持。目前,Java中實(shí)現(xiàn)多線程編程的方式流行的主要有兩種,一種是繼承Thread 類,另一種是實(shí)現(xiàn) Runnable 接口。其中通過(guò)繼承 Thread 類創(chuàng)建線程,存在的一個(gè)局限就是不能多繼承了。所以很多資料都推薦采用實(shí)現(xiàn) Runnable 接口的方式。需要說(shuō)明的是,這兩種方式在工作時(shí)的性質(zhì)都是一樣的,并沒(méi)有本質(zhì)的區(qū)別。它們都要通過(guò)實(shí)現(xiàn)run()方法來(lái)完成線程的基本任務(wù),調(diào)用Thread類的start()方法來(lái)啟動(dòng)線程。另外,這兩種方式實(shí)現(xiàn)的線程執(zhí)行完后都不能簡(jiǎn)單方便地返回執(zhí)行的結(jié)果[1]。
2 SwingWorker類的原始用途
SwingWork類是Java的Swing包中的一個(gè)類。Swing包在Java語(yǔ)言中主要是用來(lái)支持進(jìn)行圖形界面(GUI)程序的開(kāi)發(fā)的。但是,Swing包中的類并不都是線程安全的,如果使用不當(dāng)會(huì)使得程序的圖形界面反應(yīng)遲鈍;所以,從Java SE6開(kāi)始引入SwingWorker類來(lái)改善Swing程序的結(jié)構(gòu),提高界面的靈活性。
在Swing實(shí)現(xiàn)的圖形用戶界面程序中,把不同的任務(wù)分別由兩個(gè)不同的線程來(lái)實(shí)現(xiàn);一個(gè)是事件分發(fā)線程(EDT),另一個(gè)是任務(wù)線程。程序中圖形用戶界面的繪制和更新、用戶輸入或各種事件的響應(yīng),都放在EDT中實(shí)現(xiàn),耗時(shí)的任務(wù)和I/O密集型操作則放在任務(wù)線程中實(shí)現(xiàn)。這樣可以有效地提高程序的響應(yīng)性能,給用戶更好的使用體驗(yàn)。SwingWorker類就是用來(lái)實(shí)現(xiàn)這個(gè)任務(wù)線程的。SwingWorker類的設(shè)計(jì)里,已經(jīng)貼心地提供了多個(gè)方法供用戶重載選用,它們互相配合,和事件分發(fā)線程密切溝通,實(shí)現(xiàn)多方面的功能。SwingWorker是一個(gè)抽象類,支持泛型。我們可以從它繼承來(lái)實(shí)現(xiàn)任務(wù)線程。它的原型為SwingWorker< T,V>,其中T,V為兩個(gè)泛型參數(shù),T是doInBackground和get方法的返回類型,也就是線程執(zhí)行結(jié)果的返回類型;V是線程中間結(jié)果的返回類型,在GUI程序中可以用來(lái)展示任務(wù)的執(zhí)行進(jìn)度。我們重載其中的doInBackground()方法來(lái)完成基本任務(wù),調(diào)用execute()方法來(lái)啟動(dòng)任務(wù)線程。線程執(zhí)行完后調(diào)用get()方法可以取得最后的返回結(jié)果[2]。
3 SwingWorker類在一般多線程編程中的使用
SwingWorker類由于原始設(shè)計(jì)的用途是在Swing開(kāi)發(fā)的GUI程序中配合EDT線程實(shí)現(xiàn)任務(wù)線程,而GUI程序在Java程序的開(kāi)發(fā)中比重并不大,所以一般Java編程的教材資料中對(duì)這個(gè)類的介紹比較少。偶有介紹,也都是就其本意來(lái)談。其實(shí),在不涉及圖形用戶界面的情況下,SwingWorker類一樣可以用于編制普通多線程程序,有些時(shí)候比繼承Thread類或是實(shí)現(xiàn)Runnable接口更方便,可以提供更強(qiáng)的功能。
利用SwingWorker類編制普通的多線程程序其實(shí)十分簡(jiǎn)單:
首先,我們定義一個(gè)類,繼承自SwingWorker;類中重載doInBackground()方法實(shí)現(xiàn)線程的基本功能。就像繼承Thread類時(shí)或是實(shí)現(xiàn)Runnable接口的實(shí)現(xiàn)run()方法一樣。
其次,調(diào)用SwingWorker類中的Execute()方法來(lái)啟動(dòng)這個(gè)線程,類似調(diào)用Thread類start()方法來(lái)啟動(dòng)線程。
不過(guò)利用SwingWorker類來(lái)實(shí)現(xiàn)多線程,能也就是方便實(shí)現(xiàn)其他的一些功能。第一,線程運(yùn)行結(jié)束后,也就是doInBackground()方法運(yùn)行完后,可以返回一個(gè)執(zhí)行的結(jié)果。我們通過(guò)調(diào)用SwingWorker類的get()方法獲得線程的返回結(jié)果值。由于結(jié)果是必須在線程執(zhí)行完后才有,所以我們隨時(shí)都可以調(diào)用SwingWorker類的isDone()方法來(lái)判斷線程是否結(jié)束。其次,我們還可以讓線程在運(yùn)行時(shí)不斷返回一些中間結(jié)果值,這個(gè)需要push()方法和process()方法的配合,我們可以在doInBackground()方法中調(diào)用push()方法返回中間結(jié)果,重載process()來(lái)處理或利用中間結(jié)果實(shí)現(xiàn)某些功能。最后,我們甚至可以在線程運(yùn)行時(shí)取消線程的執(zhí)行。
另外,需要注意的是SwingWorker實(shí)例不可復(fù)用,每次執(zhí)行任務(wù)必須生成新的實(shí)例。
4 結(jié)束語(yǔ)
SwingWorker類不但可以在利用Swing編制的GUI程序中實(shí)現(xiàn)任務(wù)線程,在非GUI程序中也可以用來(lái)實(shí)現(xiàn)普通多線程,而且提供很多方便實(shí)用的功能。
參考文獻(xiàn)
[1] [美]Cay S.Horstmann,周立新、陳波.Java核心技術(shù) 卷I:基礎(chǔ)知識(shí)(原書(shū)第10版)[M].北京:機(jī)械工業(yè)出版社,2016:277.
[2] [美]Herbert Schidt,孫鴻飛.Java 11官方參考手冊(cè)(第11版)[M].北京:清華大學(xué)出版社,2020:196.