




版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第16章多線(xiàn)程本章要點(diǎn)了解多線(xiàn)程在Windows系統(tǒng)的執(zhí)行模式掌握實(shí)現(xiàn)線(xiàn)程的兩種方式掌握線(xiàn)程的狀態(tài)掌握使線(xiàn)程進(jìn)入各種狀態(tài)的方法掌握線(xiàn)程的優(yōu)先級(jí)掌握線(xiàn)程安全掌握線(xiàn)程同步機(jī)制掌握線(xiàn)程間的通信第16章多線(xiàn)程1、線(xiàn)程簡(jiǎn)介2、實(shí)現(xiàn)線(xiàn)程的兩種方法3、線(xiàn)程的生命周期4、操作線(xiàn)程的方法5、線(xiàn)程的優(yōu)先級(jí)6、線(xiàn)程同步7、線(xiàn)程間的通信主要內(nèi)容16.1線(xiàn)程簡(jiǎn)介世間萬(wàn)物會(huì)同時(shí)完成很多工作:例如人體同時(shí)進(jìn)行呼吸、血液循環(huán)、思考問(wèn)題等活動(dòng);用戶(hù)既可以使用計(jì)算機(jī)聽(tīng)歌,也可以使用它打印文件,而這些活動(dòng)完全可以同時(shí)進(jìn)行,這種思想在Java中被稱(chēng)為并發(fā),而將并發(fā)完成的每一件事情稱(chēng)為線(xiàn)程。16.1線(xiàn)程簡(jiǎn)介在人們的生活中,并發(fā)機(jī)制非常重要,但是并不是所有的程序語(yǔ)言都支持線(xiàn)程。在以往的程序中,多以一個(gè)任務(wù)完成后再進(jìn)行下一個(gè)項(xiàng)目的模式進(jìn)行開(kāi)發(fā),這樣下一個(gè)任務(wù)的開(kāi)始必須等待前一個(gè)任務(wù)的結(jié)束。Java語(yǔ)言提供并發(fā)機(jī)制,程序員可以在程序中執(zhí)行多個(gè)線(xiàn)程,每一個(gè)線(xiàn)程完成一個(gè)功能,并與其他線(xiàn)程并發(fā)執(zhí)行,這種機(jī)制被稱(chēng)為多線(xiàn)程。16.1線(xiàn)程簡(jiǎn)介Java中的多線(xiàn)程在每個(gè)操作系統(tǒng)中的運(yùn)行方式也存在差異,在此著重說(shuō)明多線(xiàn)程在Windows操作系統(tǒng)的運(yùn)行模式。Windows操作系統(tǒng)是多任務(wù)操作系統(tǒng),它以進(jìn)程為單位。一個(gè)進(jìn)程是一個(gè)包含有自身地址的程序,每個(gè)獨(dú)立執(zhí)行的程序都稱(chēng)為進(jìn)程,也就是正在執(zhí)行的程序。16.1線(xiàn)程簡(jiǎn)介進(jìn)程是一個(gè)用來(lái)描述處于動(dòng)態(tài)運(yùn)行狀態(tài)的應(yīng)用程序的概念,即一個(gè)進(jìn)程就是一個(gè)執(zhí)行中的程序,每個(gè)進(jìn)程都有一塊自己獨(dú)立的地址空間,并可以包含多個(gè)線(xiàn)程。這些線(xiàn)程將共享進(jìn)程的地址空間及操作系統(tǒng)分配給這個(gè)進(jìn)程的資源。線(xiàn)程一般是指進(jìn)程中的一個(gè)執(zhí)行流,多線(xiàn)程是指在一個(gè)進(jìn)程中同時(shí)運(yùn)行多個(gè)不同線(xiàn)程,每個(gè)線(xiàn)程分別執(zhí)行不同的任務(wù)。16.1線(xiàn)程簡(jiǎn)介系統(tǒng)可以分配給每個(gè)進(jìn)程一段有限的使用CPU的時(shí)間(也可以稱(chēng)為CPU時(shí)間片),CPU在這段時(shí)間中執(zhí)行某個(gè)進(jìn)程,然后下一個(gè)時(shí)間片又跳至另一個(gè)進(jìn)程中去執(zhí)行。由于CPU轉(zhuǎn)換較快,所以使得每個(gè)進(jìn)程好像是同時(shí)執(zhí)行一樣。16.1線(xiàn)程簡(jiǎn)介Windows操作系統(tǒng)的執(zhí)行模式16.1線(xiàn)程簡(jiǎn)介一個(gè)線(xiàn)程則是進(jìn)程中的執(zhí)行流程,一個(gè)進(jìn)程中可以同時(shí)包括多個(gè)線(xiàn)程,每個(gè)線(xiàn)程也可以得到一小段程序的執(zhí)行時(shí)間,這樣一個(gè)進(jìn)程就可以具有多個(gè)并發(fā)執(zhí)行的線(xiàn)程。在單線(xiàn)程中,程序代碼按調(diào)用順序依次往下執(zhí)行,如果需要一個(gè)進(jìn)程同時(shí)完成多段代碼的操作,就需要產(chǎn)生多線(xiàn)程。16.2實(shí)現(xiàn)線(xiàn)程的兩種方式16.2.1繼承Thread類(lèi)16.2.2實(shí)現(xiàn)Runnable接口16.2.1繼承Thread類(lèi)Thread類(lèi)是java.lang包中的一個(gè)類(lèi),從這個(gè)類(lèi)中實(shí)例化的對(duì)象代表線(xiàn)程,程序員啟動(dòng)一個(gè)新線(xiàn)程需要建立Thread實(shí)例。Thread類(lèi)中常用的兩個(gè)構(gòu)造方法如下:publicThread(String
threadName);publicThread();其中第一個(gè)構(gòu)造方法是創(chuàng)建一個(gè)名稱(chēng)為threadName的線(xiàn)程對(duì)象。16.2.1繼承Thread類(lèi)繼承Thread類(lèi)創(chuàng)建一個(gè)新的線(xiàn)程的語(yǔ)法如下:publicclassThreadTestextendsThread{ //...}16.2.1繼承Thread類(lèi)如果需要?jiǎng)?chuàng)建線(xiàn)程應(yīng)該先定義一個(gè)Thread類(lèi)的子類(lèi),并且覆蓋其中的run()成員方法,將線(xiàn)程執(zhí)行的程序代碼寫(xiě)在其中。Thread對(duì)象需要一個(gè)任務(wù)來(lái)執(zhí)行,任務(wù)是指線(xiàn)程在啟動(dòng)時(shí)執(zhí)行的工作,該工作的功能代碼被寫(xiě)在run()方法中。16.2.1繼承Thread類(lèi)這個(gè)run()方法必須使用如下這種語(yǔ)法格式:publicvoidrun(){ //...}注意:盡管在Thread的子類(lèi)中覆蓋了run()成員方法,但用戶(hù)不能直接調(diào)用它,而是需要通過(guò)調(diào)用Thread類(lèi)中的start()方法間接地使用它。16.2.1繼承Thread類(lèi)-注意1)start()方法的調(diào)用后并不是立即執(zhí)行多線(xiàn)程代碼,而是使得該線(xiàn)程變?yōu)榭蛇\(yùn)行態(tài)(Runnable),什么時(shí)候運(yùn)行是由操作系統(tǒng)決定的。2)如果start()方法調(diào)用一個(gè)已經(jīng)啟動(dòng)的線(xiàn)程,系統(tǒng)將拋出IllegalThreadStateException異常。16.2.1繼承Thread類(lèi)-注意main()方法線(xiàn)程啟動(dòng)由Java虛擬機(jī)負(fù)責(zé),程序員負(fù)責(zé)啟動(dòng)自己的線(xiàn)程。語(yǔ)法如下:publicstaticvoidmain(String[]args){ newThreadTest().start();}publicclassMyThreadextendsThread{publicvoidrun(){
for(intn=1;n<3;n++){for(inti=1;i<4;i++)
System.out.print(getName()+"("+i+")");System.out.println();}
System.out.println("exitfrom"+getName());}}創(chuàng)建兩個(gè)線(xiàn)程對(duì)象,分別實(shí)現(xiàn)重復(fù)顯示1~3數(shù)字的功能publicclassTest{publicstaticvoidmain(String[]args){Threadt1=newMyThread();t1.setName("T1");Threadt2=newMyThread();t2.setName("T2");t1.start();t2.start();System.out.println("exitfrom"+Thread.currentThread().getName());}}exitfrommainT2(1)T1(1)T1(2)T1(3)T2(2)T1(1)T1(2)T1(3)T2(3)exitfromT1T2(1)T2(2)T2(3)exitfromT216.2.2實(shí)現(xiàn)Runnable接口到目前為止,線(xiàn)程都是通過(guò)擴(kuò)展Thread類(lèi)來(lái)創(chuàng)建的,如果程序員需要繼承其他類(lèi)(非Thread類(lèi))并使該程序可以使用線(xiàn)程,就需要使用Runnable接口。實(shí)現(xiàn)Runnable接口的語(yǔ)法如下:publicclassMyThreadextendsObjectimplementsRunnable16.2.2實(shí)現(xiàn)Runnable接口實(shí)現(xiàn)Runnable接口的程序會(huì)創(chuàng)建一個(gè)Thread對(duì)象,并將Runnable對(duì)象與Thread對(duì)象相關(guān)聯(lián)。Thread類(lèi)中有如下兩個(gè)構(gòu)造方法:publicThread(Runnabler)publicThread(Runnable
r,Stringname)這兩個(gè)構(gòu)造方法的參數(shù)中都存在Runnable實(shí)例,使用以上構(gòu)造方法就可以將Runnable實(shí)例與Thread實(shí)例相關(guān)聯(lián)。16.2.2實(shí)現(xiàn)Runnable接口使用Runnable接口啟動(dòng)新的線(xiàn)程的步驟如下:1)建立Runnable對(duì)象。2)使用參數(shù)為Runnable對(duì)象的構(gòu)造方法創(chuàng)建Thread實(shí)例。3)調(diào)用start()方法啟動(dòng)線(xiàn)程。16.2.2實(shí)現(xiàn)Runnable接口16.2.2實(shí)現(xiàn)Runnable接口通過(guò)Runnable接口創(chuàng)建線(xiàn)程時(shí)首先需要編寫(xiě)一個(gè)實(shí)現(xiàn)Runnable接口的類(lèi),然后實(shí)例化該類(lèi)的對(duì)象,這樣就建立了Runnable對(duì)象;接下來(lái)使用相應(yīng)的構(gòu)造方法創(chuàng)建Thread實(shí)例;最后使用該實(shí)例調(diào)用Thread類(lèi)中的Start()方法啟動(dòng)線(xiàn)程。classMyThread2implements
Runnable{
privateStringname;
publicMyThread2(Stringname){
this.name=name;}public
voidrun(){
for(inti=1;i<10;i++)
System.out.println(name+"運(yùn)行:"+i);}}public
static
void
main(String[]args){
new
Thread(new
MyThread2("th1")).start();
new
Thread(new
MyThread2("th2")).start();/*MyThread2th1=newMyThread2("th1");Threadthobj1=newThread(th1);MyThread2th2=newMyThread2("th2");Threadthobj2=newThread(th2);thobj1.start();thobj2.start();*/}16.2.2實(shí)現(xiàn)Runnable接口實(shí)現(xiàn)Runnable接口比繼承Thread類(lèi)所具有的優(yōu)勢(shì):適合多個(gè)相同的程序代碼的線(xiàn)程去處理同一個(gè)資源可以避免java中的單繼承的限制增加程序的健壯性,代碼可以被多個(gè)線(xiàn)程共享,代碼和數(shù)據(jù)獨(dú)立16.3線(xiàn)程的生命周期線(xiàn)程生命周期中的各種狀態(tài)16.3線(xiàn)程的生命周期線(xiàn)程具有生命周期,其中包含7種狀態(tài),分別為出生狀態(tài)、就緒狀態(tài)、運(yùn)行狀態(tài)、等待狀態(tài)、休眠狀態(tài)、阻塞狀態(tài)和死亡狀態(tài)。出生狀態(tài)就是用戶(hù)在創(chuàng)建線(xiàn)程時(shí)處于的狀態(tài),在用戶(hù)使用該線(xiàn)程實(shí)例調(diào)用start()方法之前線(xiàn)程都處于出生狀態(tài);當(dāng)用戶(hù)調(diào)用start()方法后,線(xiàn)程處于就緒狀態(tài)(又被稱(chēng)為可執(zhí)行狀態(tài));當(dāng)線(xiàn)程得到系統(tǒng)資源后就進(jìn)入運(yùn)行狀態(tài)。16.3線(xiàn)程的生命周期一旦線(xiàn)程進(jìn)入可執(zhí)行狀態(tài),它會(huì)在就緒與運(yùn)行狀態(tài)下輾轉(zhuǎn),同時(shí)也有可能進(jìn)入等待、休眠、阻塞或死亡狀態(tài)。當(dāng)處于運(yùn)行狀態(tài)下的線(xiàn)程調(diào)用Thread類(lèi)中的wait()方法,該線(xiàn)程處于等待狀態(tài),進(jìn)入等待狀態(tài)的線(xiàn)程必須調(diào)用Thread類(lèi)中的notify()方法才能被喚醒,而notifyAll()方法是將所有處于等待狀態(tài)下的線(xiàn)程喚醒;16.3線(xiàn)程的生命周期當(dāng)線(xiàn)程調(diào)用Thread類(lèi)中的sleep()方法,則會(huì)進(jìn)入休眠狀態(tài)。如果一個(gè)線(xiàn)程在運(yùn)行狀態(tài)下發(fā)出輸入/輸出請(qǐng)求,該線(xiàn)程將進(jìn)入阻塞狀態(tài),在其等待輸入/輸出結(jié)束時(shí)線(xiàn)程進(jìn)入就緒狀態(tài),對(duì)于阻塞的線(xiàn)程來(lái)說(shuō),即使系統(tǒng)資源空閑,線(xiàn)程依然不能回到運(yùn)行狀態(tài);當(dāng)線(xiàn)程的run()方法執(zhí)行完畢時(shí),線(xiàn)程進(jìn)入死亡狀態(tài)。16.3線(xiàn)程的生命周期雖然多線(xiàn)程看起來(lái)像同時(shí)執(zhí)行,但事實(shí)上在同一時(shí)間點(diǎn)上只有一個(gè)線(xiàn)程被執(zhí)行,只是線(xiàn)程之間切換較快,所以才會(huì)使人產(chǎn)生線(xiàn)程是同時(shí)進(jìn)行的假象。在Windows操作系統(tǒng)中,系統(tǒng)會(huì)為每個(gè)線(xiàn)程分配一小段CPU時(shí)間片,一旦CPU時(shí)間片結(jié)束就會(huì)將當(dāng)前線(xiàn)程換為下一個(gè)線(xiàn)程,即使該線(xiàn)程沒(méi)有結(jié)束的情況下。16.3線(xiàn)程的生命周期根據(jù)圖16-5所示,可以總結(jié)出使線(xiàn)程進(jìn)入阻塞狀態(tài)有以下幾種可能。調(diào)用sleep()方法。調(diào)用wait()方法。等待輸入/輸出完成。16.3線(xiàn)程的生命周期當(dāng)線(xiàn)程處于阻塞狀態(tài)后,可通過(guò)以下幾種方式使線(xiàn)程再次進(jìn)入就緒狀態(tài)。線(xiàn)程調(diào)用notify()方法。線(xiàn)程調(diào)用notifyAll()方法。線(xiàn)程調(diào)用interrupt()方法。線(xiàn)程的休眠時(shí)間結(jié)束。
輸入/輸出結(jié)束。16.4操作線(xiàn)程的方法16.4.1線(xiàn)程的休眠16.4.2線(xiàn)程的加入16.4.3線(xiàn)程的中斷16.4.4線(xiàn)程的禮讓16.4.1線(xiàn)程的休眠一種能控制線(xiàn)程行為的方法是調(diào)用sleep()方法,sleep()方法需要一個(gè)參數(shù)用于指定該線(xiàn)程休眠的時(shí)間,該時(shí)間使用毫秒為單位。它通常是在run()方法內(nèi)的循環(huán)中被使用。sleep()方法的語(yǔ)法如下:try{ Thread.sleep(2000);}catch(InterruptedExceptione){
e.printStackTrace();}public
voidrun(){
System.out.println("開(kāi)始執(zhí)行線(xiàn)程。。。");
System.out.println("進(jìn)入睡眠狀態(tài)。。。");
try{Thread.sleep(3000);}catch(InterruptedExceptione){
e.printStackTrace();}
System.out.println("線(xiàn)程結(jié)束。。。");}16.4.2線(xiàn)程的加入如果當(dāng)前某程序?yàn)槎嗑€(xiàn)程程序,假如存在一個(gè)線(xiàn)程A,現(xiàn)在需要插入線(xiàn)程B,并要求線(xiàn)程B先執(zhí)行完畢,然后再繼續(xù)執(zhí)行線(xiàn)程A,此時(shí)可以使用Thread類(lèi)中的join()方法來(lái)完成。這就好比此時(shí)正在看電視,卻突然有人上門(mén)收水費(fèi),必須付完水費(fèi)后才能繼續(xù)看電視。當(dāng)某個(gè)線(xiàn)程使用join()方法加入到另外一個(gè)線(xiàn)程時(shí),另一個(gè)線(xiàn)程會(huì)等待該線(xiàn)程執(zhí)行完畢再繼續(xù)執(zhí)行。16.4.2線(xiàn)程的加入為什么要用join()方法在很多情況下,主線(xiàn)程生成并起動(dòng)了子線(xiàn)程,如果子線(xiàn)程里要進(jìn)行大量的耗時(shí)的運(yùn)算,主線(xiàn)程往往將于子線(xiàn)程之前結(jié)束,但是如果主線(xiàn)程處理完其他的事務(wù)后,需要用到子線(xiàn)程的處理結(jié)果,也就是主線(xiàn)程需要等待子線(xiàn)程執(zhí)行完成之后再結(jié)束,這個(gè)時(shí)候就要用到j(luò)oin()方法了。classThread1extendsThread{privateStringname;
publicThread1(Stringname){this.name=name;}
public
voidrun(){
for(inti=0;i<3;i++){
System.out.println("子線(xiàn)程"+name+"運(yùn)行:"+i);
try{
sleep((int)Math.random()*10);}catch(InterruptedExceptione){
e.printStackTrace();}
}
}
}public
static
void
main(String[]args){
System.out.println(Thread.currentThread().getName()+"主線(xiàn)程運(yùn)行開(kāi)始!");
Thread1mTh1=newThread1("A");Thread1mTh2=newThread1("B");mTh1.start();mTh2.start();
System.out.println(Thread.currentThread().getName()+"主線(xiàn)程運(yùn)行結(jié)束!");
}main主線(xiàn)程運(yùn)行開(kāi)始!main主線(xiàn)程運(yùn)行結(jié)束!子線(xiàn)程B運(yùn)行:0子線(xiàn)程A運(yùn)行:0子線(xiàn)程B運(yùn)行:1子線(xiàn)程A運(yùn)行:1子線(xiàn)程B運(yùn)行:2子線(xiàn)程A運(yùn)行:2public
static
void
main(String[]args){…
Thread1mTh1=newThread1("A");Thread1mTh2=newThread1("B");mTh1.start();mTh2.start();
try{mTh1.join();mTh2.join();}catch(InterruptedExceptione){
e.printStackTrace();}…}main主線(xiàn)程運(yùn)行開(kāi)始!子線(xiàn)程B運(yùn)行:0子線(xiàn)程B運(yùn)行:1子線(xiàn)程B運(yùn)行:2子線(xiàn)程A運(yùn)行:0子線(xiàn)程A運(yùn)行:1子線(xiàn)程A運(yùn)行:2main主線(xiàn)程運(yùn)行結(jié)束!16.4.3線(xiàn)程的中斷以前使用stop()方法停止線(xiàn)程,但當(dāng)前版本的JDK早已廢除了stop()方法,同時(shí)也不建議使用stop()方法來(lái)停止一個(gè)線(xiàn)程的運(yùn)行?,F(xiàn)在提倡在run()方法中使用無(wú)限循環(huán)的形式,然后使用一個(gè)布爾型標(biāo)記控制循環(huán)的停止。class
ThreadTest
extendsThread{
private
intcount=10;
public
voidrun(){
while(true){
System.out.print(count+"");
if(--count==0){
return;}}}}16.4.4線(xiàn)程的禮讓Thread類(lèi)中使用yield()方法表示禮讓?zhuān)皇墙o當(dāng)前正處于運(yùn)行狀態(tài)下的線(xiàn)程一個(gè)提醒,告知它可以將資源禮讓給其他線(xiàn)程。但這僅僅是一種暗示,沒(méi)有任何一種機(jī)制保證當(dāng)前線(xiàn)程會(huì)將資源禮讓。對(duì)于支持多任務(wù)的操作系統(tǒng)來(lái)說(shuō),不需要調(diào)用yeild()方法,因?yàn)椴僮飨到y(tǒng)會(huì)為線(xiàn)程自動(dòng)分配CPU時(shí)間片來(lái)執(zhí)行。16.5線(xiàn)程的優(yōu)先級(jí)每個(gè)線(xiàn)程都具有各自的優(yōu)先級(jí),線(xiàn)程的優(yōu)先級(jí)可以在程序中表明該線(xiàn)程的重要性,如果有很多線(xiàn)程處于就緒狀態(tài),系統(tǒng)會(huì)根據(jù)優(yōu)先級(jí)來(lái)決定首先使哪個(gè)線(xiàn)程進(jìn)入運(yùn)行狀態(tài)。但這并不意味著低優(yōu)先級(jí)的線(xiàn)程得不到運(yùn)行,而只是它運(yùn)行的幾率比較小,比如垃圾回收線(xiàn)程的優(yōu)先級(jí)就較低。16.5線(xiàn)程的優(yōu)先級(jí)Thread類(lèi)中包含的靜態(tài)成員變量代表了線(xiàn)程的某些優(yōu)先級(jí),比如Thread.MIN_PRIORITY(常數(shù)1)、Thread.MAX_PRIORITY(常數(shù)10)、Thread.NORM_PRIORITY(常數(shù)5)。其中每個(gè)線(xiàn)程的優(yōu)先級(jí)都在Thread.MIN_PRIORITY~Thread.MAX_PRIORITY之間,在默認(rèn)情況下其優(yōu)先級(jí)都是Thread.NORM_PRIORITY。每個(gè)新產(chǎn)生的線(xiàn)程都繼承了父線(xiàn)程的優(yōu)先級(jí)。16.5線(xiàn)程的優(yōu)先級(jí)在多任務(wù)操作系統(tǒng)中,每個(gè)線(xiàn)程都會(huì)得到一小段CPU時(shí)間片運(yùn)行,在時(shí)間結(jié)束時(shí),將輪換另一個(gè)線(xiàn)程進(jìn)入運(yùn)行狀態(tài),這時(shí)系統(tǒng)會(huì)選擇與當(dāng)前線(xiàn)程優(yōu)先級(jí)相同的線(xiàn)程予以運(yùn)行。系統(tǒng)始終選擇就緒狀態(tài)下優(yōu)先級(jí)較高的線(xiàn)程進(jìn)入運(yùn)行狀態(tài)。線(xiàn)程的優(yōu)先級(jí)可以使用setPriority()方法調(diào)整,如果使用該方法設(shè)置的優(yōu)先級(jí)不在1~10之內(nèi),將產(chǎn)生一個(gè)IllegalArgumentException異常。16.5線(xiàn)程的優(yōu)先級(jí)16.5線(xiàn)程的優(yōu)先級(jí)在圖16-9中,優(yōu)先級(jí)為5的線(xiàn)程A首先得到CPU時(shí)間片;當(dāng)該時(shí)間結(jié)束后,輪換到與線(xiàn)程A相同優(yōu)先級(jí)的線(xiàn)程B;當(dāng)線(xiàn)程B的運(yùn)行時(shí)間結(jié)束后,會(huì)繼續(xù)輪換到線(xiàn)程A,直到線(xiàn)程A與線(xiàn)程B都執(zhí)行完畢,才會(huì)輪換到線(xiàn)程C;當(dāng)線(xiàn)程C結(jié)束后,最后才會(huì)輪到線(xiàn)程D。classMyThread51extendsThread{
publicMyThread51(Stringname){
super(name);}
public
voidrun(){
for(inti=0;i<5;i++){
System.out.println(Thread.currentThread().getName()+"("+Thread.currentThread().getPriority()+")"+",loop"+i);}}
}
public
static
void
main(String[]args){
System.out.println(Thread.currentThread().getName()+"("+Thread.currentThread().getPriority()+")");Threadt1=newMyThread51("t1");Threadt2=newMyThread51("t2");t1.setPriority(1);t2.setPriority(10);
t1.start();t2.start();
}main(5)t1(1),loop0t1(1),loop1t1(1),loop2t1(1),loop3t1(1),loop4t2(10),loop0t2(10),loop1t2(10),loop2t2(10),loop3t2(10),loop416.6線(xiàn)程同步16.6.1線(xiàn)程安全16.6.2線(xiàn)程同步機(jī)制16.6.1線(xiàn)程安全所以在編寫(xiě)多線(xiàn)程程序時(shí),應(yīng)該考慮到線(xiàn)程安全問(wèn)題。實(shí)質(zhì)上線(xiàn)程安全問(wèn)題來(lái)源于兩個(gè)線(xiàn)程同時(shí)存取單一對(duì)象的數(shù)據(jù)。在一個(gè)時(shí)刻只能被一個(gè)線(xiàn)程訪(fǎng)問(wèn)的資源稱(chēng)為臨界資源,而訪(fǎng)問(wèn)臨界資源的那段代碼被稱(chēng)為臨界區(qū)。臨界區(qū)的使用必須互斥地進(jìn)行,即一個(gè)線(xiàn)程在臨界區(qū)中執(zhí)行代碼時(shí),其他線(xiàn)程不能進(jìn)入臨界區(qū)。16.6.1線(xiàn)程安全在代碼中判斷當(dāng)前票數(shù)是否大于0,如果大于0則執(zhí)行將該票出售給乘客功能,但當(dāng)兩個(gè)線(xiàn)程同時(shí)訪(fǎng)問(wèn)這段代碼時(shí)(假如這時(shí)只剩下一張票),第一個(gè)線(xiàn)程將票售出,與此同時(shí)第二個(gè)線(xiàn)程也已經(jīng)執(zhí)行完成判斷是否有票的操作,并得出結(jié)論票數(shù)大于0,于是它也執(zhí)行售出操作,這樣就會(huì)產(chǎn)生負(fù)數(shù)。class
ThreadSafeTest
implements
Runnable{
intnum=10;//設(shè)置當(dāng)前總票數(shù)
public
voidrun(){
while(num>0){
try{Thread.sleep(100);}catch(Exceptione){
e.printStackTrace();}
System.out.println("tickets"+num--);}}}
public
static
void
main(String[]args){
ThreadSafeTestt=new
ThreadSafeTest();ThreadtA=new
Thread(t);
//以該類(lèi)對(duì)象分別實(shí)例化4個(gè)線(xiàn)程
ThreadtB=new
Thread(t);ThreadtC=new
Thread(t);ThreadtD=new
Thread(t);
tA.start();//分別啟動(dòng)線(xiàn)程
tB.start();
tC.start();
tD.start();}tickets10tickets8tickets9tickets7tickets6tickets4tickets5tickets6tickets3tickets2tickets1tickets0tickets-1tickets-216.6.2線(xiàn)程同步機(jī)制如何解決資源共享的問(wèn)題?基本上所有解決多線(xiàn)程資源沖突問(wèn)題都會(huì)采用給定時(shí)間只允許一個(gè)線(xiàn)程訪(fǎng)問(wèn)共享資源,這時(shí)就需要給共享資源上一道鎖。為了解決多線(xiàn)程并發(fā)操作可能引起的數(shù)據(jù)混亂,在java中,引入對(duì)象“互斥鎖”,以保證共享數(shù)據(jù)操作的完整性。16.6.2線(xiàn)程同步機(jī)制1)同步塊在Java中提供了同步機(jī)制,可以有效地防止資源沖突。同步機(jī)制使用synchronized關(guān)鍵字。
synchronized(Object){}Object為任意一個(gè)對(duì)象,每個(gè)對(duì)象都存在一個(gè)標(biāo)志位,并具有兩個(gè)值,分別為0和1。一個(gè)線(xiàn)程運(yùn)行到同步塊時(shí)首先檢查該對(duì)象的標(biāo)志位,如果為0狀態(tài),表明此同步塊中存在其他線(xiàn)程在運(yùn)行。這時(shí)該線(xiàn)程就處于就緒狀態(tài),直到處于同步塊中的線(xiàn)程執(zhí)行完同步塊中的代碼為止。這時(shí)該對(duì)象的標(biāo)識(shí)位被設(shè)置為1,該線(xiàn)程才能執(zhí)行同步塊中的代碼,并將Object對(duì)象的標(biāo)識(shí)位設(shè)置為0,防止其他線(xiàn)程執(zhí)行同步塊中的代碼。
public
voidrun(){
synchronized(""){
while(num>0){
try{Thread.sleep(100);}catch(Exceptione){
e.printStackTrace();}
System.out.println("tickets"+num--);}
}}16.6.2線(xiàn)程同步機(jī)制2)同步方法同步方法就是在方法前面修飾synchronized關(guān)鍵字的方法,其語(yǔ)法如下。
synchronizedvoidf(){}當(dāng)某個(gè)對(duì)象調(diào)用了同步
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 混凝土硬化路施工方案
- 板房防水卷材施工方案
- TSHAEPI 014-2024 溫室氣體(二氧化碳和甲烷)走航監(jiān)測(cè)技術(shù)規(guī)范
- 二零二五年度網(wǎng)絡(luò)安全就業(yè)協(xié)議書(shū)協(xié)議內(nèi)容詳盡規(guī)范
- 二零二五年度股權(quán)投資公司股東合作協(xié)議
- 2025年度軟裝行業(yè)市場(chǎng)監(jiān)測(cè)與風(fēng)險(xiǎn)評(píng)估合同
- 二零二五年度廣東省房屋租賃合同租賃保險(xiǎn)合作協(xié)議
- 二零二五年度娛樂(lè)產(chǎn)業(yè)動(dòng)漫IP授權(quán)使用勞動(dòng)合同
- 二零二五年度店鋪轉(zhuǎn)讓定金及品牌授權(quán)使用合同
- 二零二五年度商業(yè)空間合租租賃及稅務(wù)咨詢(xún)合同
- 2023年湖南食品藥品職業(yè)學(xué)院高職單招(英語(yǔ))試題庫(kù)含答案解析
- GB/T 39096-2020石油天然氣工業(yè)油氣井油管用鋁合金管
- 爐外精煉說(shuō)課
- GB/T 23111-2008非自動(dòng)衡器
- GB/T 18877-2020有機(jī)無(wú)機(jī)復(fù)混肥料
- 三大構(gòu)成之立體構(gòu)成-課件
- DB11 938-2022 綠色建筑設(shè)計(jì)標(biāo)準(zhǔn)
- 最新家政服務(wù)員培訓(xùn)課件
- 2022譯林版新教材高一英語(yǔ)必修二單詞表及默寫(xiě)表
- 全國(guó)青少年機(jī)器人技術(shù)等級(jí)考試:二級(jí)培訓(xùn)全套課件
- TB T2075-《電氣化鐵道接觸網(wǎng)零部件》
評(píng)論
0/150
提交評(píng)論