




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
第9章多線程9.1進程與線程
9.2認識線程
9.3線程的狀態
9.4線程操作的一些方法
9.1進?程?與?線?程
進程是程序的一次動態執行過程,它經歷了從代碼加載、執行到執行完畢的一個完整過程。這個過程也是進程本身從產生、發展到最終消亡的過程。多進程操作系統能同時運行多個進程(程序),由于CPU具備分時機制,所以每個進程都能循環獲得自己的CPU時間片。由于CPU執行速度非常快,使得所有程序好像是在“同時”運行一樣。
線程是比進程更小的執行單位,線程是進程內部單一的一個順序控制流。所謂多線程,是指一個進程在執行過程中可以產生多個線程,這些線程可以同時存在、同時運行,形成多條執行線索。一個進程可能包含了多個同時執行的線程。
多線程是實現并發機制的一種有效手段。進程和線程一樣,都是實現并發的一個基本單位。
線程和進程的主要差別體現在以下兩個方面:
(1)同樣作為基本的執行單元,線程是劃分得比進程更小的執行單位。
(2)每個進程都有一段專用的內存區域。與此相反,線程卻共享內存單元(包括代碼和數據),通過共享的內存單元來實現數據交換、實時通信與必要的同步操作。多線程的應用范圍很廣。在一般情況下,程序的某些部分同特定的事件或資源聯系在一起,同時又不想為它暫停程序其他部分的執行,在這種情況下,就可以考慮創建一個線程,令它與那個事件或資源關聯到一起,并讓其獨立于主程序運行。通過使用線程,可以避免用戶在運行程序和得到結果之間停頓,還可以讓一些任務(如打印任務)在后臺運行,用戶則在前臺繼續完成其他工作。總之,利用多線程技術,編程人員可以方便地開發出能同時處理多個任務的功能強大的應用程序。
9.2認識線程
在傳統的程序語言中,運行的順序總是必須順著程序的流程來走,遇到if-else語句就加以判斷,遇到for、while等循環會多繞幾個圈,最后程序還是按著一定的程序走,且一次只能運行一個程序塊。Java的“多線程”打破了這種傳統的束縛。例如,有些包含循環的線程可能要使用比較長的一段時間來運算,此時便可讓另一個線程來做其他處理。本節將用一個簡單的程序來說明單一線程與多線程的區別。ThreadDemo9_1是單一線程的范例,其程序代碼編寫方法與前幾節的程序代碼并沒有什么不同。
【例9-1】ThreadDemo9_1.java。程序說明:
(1)第15~21行定義了run()方法,用循環輸出10個連續的字符串。
(2)第5行創建TestThread對象之后調用run()方法,輸出“TestThread在運行”,最后執行main()方法中的循環,輸出“main線程在運行”。
從本例中可看出,要想運行main()方法中的循環,必須要等TestThread類中的run()方法執行完之后才可以運行,這便是單一線程的缺陷。在Java中,是否可以同時運行第9行與第19行的語句,使得“main線程在運行”和“TestThread在運行”交錯輸出呢?答案是肯定的,其方法是:在Java中激活多個線程。那么,該如何激活線程呢?如果在類里要激活線程,必須先做好下面兩個準備:
(1)線程必須擴展自Thread類,使自己成為它的子類。
(2)線程的處理必須編寫在run()方法內。
9.2.1通過繼承Thread類實現多線程
Thread存放在java.lang類庫中,但并不需加載java.lang類庫,因為它會自動加載。此外,run()方法是定義在Thread類中的一個方法,因此把線程的程序代碼編寫在run()方法內,事實上所做的就是覆蓋操作。因此要使一個類可激活線程,必須按照下面的語法來編寫:從運行結果中可以發現,兩行輸出是交替進行的。也就是說,程序是采用多線程機制運行的。與之前的程序相比,修改后的程序第13行TestThread類繼承了Thread類,第5行調用的不再是run()方法,而是start()方法。所以,要啟動線程,必須調用Thread類之中的start()方法,而調用了start()方法,也就是調用了run()方法。
9.2.2通過實現Runnable接口實現多線程
Java程序只允許單一繼承,即一個子類只能有一個父類,所以在Java中如果一個類繼承了某一個類,同時又想采用多線程技術,就不能用Thread類產生線程,因為Java不允許多繼承,這時就要用Runnable接口來創建線程。程序說明:
(1)第5行實例化一個TestThread類的對象。
(2)第6行通過TestThread類(Runnable接口的子類)去實例化一個Thread類的對象,之后調用start()方法啟動多線程。
(3)第14行TestThread類實現了Runnable接口,同時復寫了Runnable接口之中的run()方法。也就是說,此類為一多線程實現類。
從輸出結果可以發現,無論繼承了Thread類還是實現了Runnable接口,運行結果都是一樣的。為什么實現了Runnable接口還需要調用Thread類中的start()方法才能啟動多線程呢?通過查找JDK文檔就可以發現,在Runnable接口中只有一個run()方法,如圖9-1所示。圖9-1Runnable接口中的方法列表從圖9-1中可以看出,在Runnable接口中并沒有start()方法,所以一個類實現了Runnable接口也必須用Thread類中的start()方法來啟動多線程。這點可以通過查找JDK文檔中的Thread類知道。在Thread類之中,有這樣一個構造方法:
publicThread(Runnabletarget)
由此構造方法可以看出,可以將一個Runnable接口的實例化對象作為參數去實例化Thread類對象。在實際開發中,希望讀者盡可能使用Runnable接口去實現多線程機制。9.2.3兩種多線程實現機制的比較
由9.2.1節和9.2.2節可以看出,不管實現了Runnable接口還是繼承了Thread類其結果都是一樣的,那么這兩者之間有什么關系呢?讀者可以通過查看JDK文檔發現二者之間的聯系,如圖9-2所示。圖9-2Thread類與Runnable接口的關系從圖9-2中可以看出,Thread類實現了Runnable接口。也就是說,Thread類也是Runnable接口的一個子類。那么兩者之間除了這些聯系之外還有什么區別呢?下面通過編寫一個應用程序來進行比較分析。下面程序是一個模擬鐵路售票系統的范例,實現四個售票點發售某日某次列車的車票20張,一個售票點用一個線程來表示。
【例9-4】ThreadDemo9_3.java。下例由ThreadDemo9_3的程序修改而成,這里讓main()方法中產生四個線程。
【例9-5】
修改后的ThreadDemo9_3.java。由于程序的輸出結果過長,所以只截取了后面一部分,但從這部分輸出結果中可以看出,這里啟動了四個線程對象,這四個線程對象各自占有各自的資源,所以可以得出結論:用Thread類實際上無法達到資源共享的目的。
那么實現Runnable接口會如何呢?下面這個例子也修改自ThreadDemo9_3,讀者可以觀察一下輸出結果。
【例9-6】ThreadDemo9_4.java。從上面的程序中可以看出,第7行到第10行啟動了四個線程,從程序的輸出結果來看,盡管啟動了四個線程對象,但是結果都操縱了同一個資源,實現了資源共享的目的。
可見,實現Runnable接口相對于繼承Thread類來說具有如下顯著優勢:
(1)適合多個相同程序代碼的線程去處理同一資源的情況,把虛擬CPU(線程)同程序的代碼、數據有效分離,較好地體現了面向對象的設計思想。
(2)可以避免由于Java的單繼承特性帶來的局限。開發中經常碰到這樣一種情況,即:當要將已經繼承了某一個類的子類放入多線程中時,由于一個類不能同時有兩個父類,所以不能用繼承Thread類的方式,那么就只能采用實現Runnable接口的方式。
(3)增強了程序的健壯性,代碼能夠被多個線程共享,代碼與數據是獨立的。當多個線程的執行代碼來自同一個類的實例時,稱它們共享相同的代碼。多個線程可以操作相同的數據,與它們的代碼無關。當共享訪問相同的對象時,共享相同的數據。當線程被構造時,需要的代碼和數據通過一個對象作為構造函數實參傳遞進去,這個對象就是一個實現了Runnable接口的類的實例。
事實上,幾乎所有多線程應用都可用第二種方式,即實現Runnable接口。
9.3線?程?的?狀?態
每個Java程序都有一個缺省的主線程。對于Java應用程序,主線程是main()方法執行的線索;對于Applet程序,主線程是指揮瀏覽器加載并執行JavaApplet程序的線索。要想實現多線程,必須在主線程中創建新的線程對象。任何線程一般具有五種狀態,即創建、就緒、運行、阻塞、終止。線程狀態的轉移與方法之間的關系可用圖9-3來表示。圖9-3線程的狀態轉換
1.創建狀態
在程序中用構造方法創建了一個線程對象后,新的線程對象便處于新建狀態,此時它已經有了相應的內存空間和其他資源,但還處于不可運行狀態。創建一個線程對象可采用線程構造方法來實現,如Threadthread=newThread();。
2.就緒狀態
創建線程對象后,調用該線程的start()方法就可以啟動線程。當線程啟動時,線程進入就緒狀態。此時,線程將進入線程隊列排隊,等待CPU服務,這表明它已經具備了運行
條件。
3.運行狀態
當就緒狀態的線程被調用并獲得處理器資源時,線程就進入了運行狀態。此時,自動調用該線程對象的run()方法。run()方法定義了該線程的操作和功能。
4.阻塞狀態
一個正在執行的線程在某些特殊情況下,如被人為掛起或需要執行耗時的輸入/輸出操作時,將讓出CPU并暫時中止自己的執行,進入阻塞狀態。在可執行狀態下,如果調用sleep()、suspend()、wait()等方法,線程都將進入阻塞狀態。阻塞時,線程不能進入排隊隊列,只有當引起阻塞的原因被消除后,線程才可以轉入就緒狀態。
5.終止狀態
線程調用stop()方法時或run()方法執行結束后,線程即處于終止狀態。處于終止狀態的線程不具有繼續運行的能力。
9.4線程操作的一些方法
在Java實現多線程的程序中,雖然Thread類實現了Runnable接口,但是操作線程的主要方法并不在Runnable接口中,而是在Thread類中。表9-1列出了Thread類中的主要方法。表9-1Thread類中的主要方法9.4.1取得和設置線程的名稱
在Thread類中,可以通過getName()方法取得線程的名稱,通過setName()方法設置線程的名稱。線程的名稱一般在啟動線程前設置,但也允許為已經運行的線程設置名稱。允許兩個Thread對象有相同的名字,但為了清晰,應該盡量避免這種情況的發生。
另外,如果程序并沒有為線程指定名稱,則系統會自動為線程分配一個名稱。
【例9-7】GetNameThreadDemo.java。程序說明:
(1)第1行聲明一個GetNameThreadDemo類,此類繼承自Thread類,之后3~7行復寫Thread類中的run()方法。
(2)第8~14行聲明一個printMsg()方法,此方法用于取得當前線程的信息。在第11行,通過Thread類中的currentThread()方法,返回一個Thread類的實例化對象。由表9-1可知,此方法返回當前正在運行的線程,即返回正在調用此方法的線程。第12行通過調用Thread類中的getName()方法,返回當前運行線程的名稱。
(3)第6行和第21行分別調用了printMsg()方法,但第6行從多線程的run()方法中調用,而第21行從main()方法中調用。為什么程序中輸出的運行線程的名稱中會有一個main呢?這是因為main()方法也是一個線程,實際上在命令行中運行Java命令時,就啟動了一個JVM的進程,默認情況下此進程會產生兩個線程:一個是main()方法線程,另外一個就是垃圾回收(GC)線程。
下例介紹如何在線程中設置線程的名稱。
【例9-8】SetNameThreadDemo.java。9.4.2線程是否啟動的判斷
通過Thread類中的start()方法通知線程規劃器這個新線程已準備就緒,而且應當在規劃器的最早方便時間調用它的run()方法。在程序中也可以通過isAlive()方法來測試線程是否已經啟動而且仍然在啟動。
【例9-9】StartThreadDemo.java。程序說明:
(1)第20行在線程運行之前調用isAlive()方法,判斷線程是否啟動,但在此處并沒有啟動,所以返回“false”,表示線程未啟動。
(2)第22行在啟動線程之后調用isAlive()方法,此時線程已經啟動,所以返回“true”。
(3)第28行在main()方法快結束時調用isAlive()方法,此時的狀態不再固定,有可能是true,也有可能是false。9.4.3后臺線程與setDaemon()方法
對Java程序來說,只要還有一個前臺線程在運行,這個進程就不會結束;如果一個進程中只有后臺線程在運行,這個進程就會結束。前臺線程是相對于后臺線程而言的,前面所介紹的線程都是前臺線程。那么什么樣的線程是后臺線程呢?如果某個線程對象在啟動(調用start()方法)之前調用了setDaemon(true)
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 石家莊勞務派遣合同協議
- 私人集資建房合同協議
- 票據印刷協議書范本
- 租賃合同未到期搬遷協議
- 私人車位租售合同協議
- 礦石銷售中介合同協議
- 研發委托開發合同協議
- 真空上料器采購合同協議
- 租賃房屋合同解除協議
- 私人外墻清洗合同協議
- GB/T 30663-2024人才測評服務規范
- 《文化學概論》第三章-文化的起源及其發展-38
- 2024年高考新課標全國卷政治試題分析及2025屆高考復習備考建議
- 公立醫院醫療服務價格制度
- 突發環境事件應急預案評審會匯報課件-(模板)
- JGJ+196-2010建筑施工塔式起重機安裝、使用、拆卸安全技術規程
- 跌倒不良事件分析匯報課件
- 一氧化碳檢測報警器標準裝置技術報告
- 交通事故賠償起訴狀范例合集
- JT∕T1180.4-2018交通運輸企業安全生產標準化建設基本規范第4部分:道路普貨運輸
- 《再別康橋》 統編版高中語文選擇性必修下冊
評論
0/150
提交評論