Java語言程序設(shè)計(第三版-清華)第8章new_第1頁
Java語言程序設(shè)計(第三版-清華)第8章new_第2頁
Java語言程序設(shè)計(第三版-清華)第8章new_第3頁
Java語言程序設(shè)計(第三版-清華)第8章new_第4頁
Java語言程序設(shè)計(第三版-清華)第8章new_第5頁
已閱讀5頁,還剩62頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

第九章線程1目錄Java中的線程線程的生命周期Thread的子類創(chuàng)立線程使用Runable接口線程的常用方法線程的優(yōu)先級線程同步在同步方法中使用wait()、notify和notifyAll()方法掛起、恢復(fù)和終止線程本章小結(jié)2線程的概念進程和線程的區(qū)別〔Example9_11)進程一個獨立程序的每一次運行稱為一個進程,例如用字處理軟件編輯文稿時,同時翻開mp3播放程序聽音樂,這兩個獨立的程序在同時運行,稱為兩個進程設(shè)置一個進程要占用相當(dāng)一局部處理器時間和內(nèi)存資源大多數(shù)操作系統(tǒng)不允許進程訪問其他進程的內(nèi)存空間,進程間的通信很不方便,編程模型比較復(fù)雜進程通信方式共享存儲器系統(tǒng)、消息傳到機制、管道通信3線程一個程序中多段代碼同時并發(fā)執(zhí)行,稱為多線程通過多線程,一個進程外表上看同時可以執(zhí)行一個以上的任務(wù)——并發(fā)創(chuàng)立線程比創(chuàng)立進程開銷要小得多,線程之間的協(xié)作和數(shù)據(jù)交換也比較容易(進程獨站資源)線程間共享資源〔內(nèi)存、代碼、數(shù)據(jù)〕有利于并行處理線程的概念(續(xù))4線程的狀態(tài)與生命周期新建:當(dāng)一個Thread類或其子類的對象被聲明并創(chuàng)立時,新生的線程對象處于新建狀態(tài)。此時它已經(jīng)有了相應(yīng)的內(nèi)存空間和其他資源。就緒狀態(tài):線程等待CPU運行狀態(tài):start()方法開始執(zhí)行中斷(阻塞)狀態(tài):sleep(),wait(),I/O完成or發(fā)布I/O請求sleep():使當(dāng)前線程進入等待狀態(tài),參數(shù)設(shè)定其等待時間wait():使當(dāng)前線程進入等待狀態(tài),調(diào)用nofify(),ornotifyAll(),使其重新進入線程等待隊列死亡:run()方法完成stop()方法被調(diào)用5LifeCycleofThread6誕生狀態(tài)線程剛剛被創(chuàng)立就緒狀態(tài)線程的start方法已被執(zhí)行線程已準(zhǔn)備好運行運行狀態(tài)處理機分配給了線程,線程正在運行阻塞狀態(tài)〔Blocked〕在線程發(fā)出輸入/輸出請求且必須等待其返回遇到用synchronized標(biāo)記的方法而未獲得其監(jiān)視器暫時不能進入執(zhí)行時休眠狀態(tài)〔Sleeping〕執(zhí)行sleep方法而進入休眠死亡狀態(tài)線程已完成或退出線程的幾種根本狀態(tài)(續(xù))7主線程:Java應(yīng)用程序總是從主類的main方法開始執(zhí)行。當(dāng)JVM加載代碼,發(fā)現(xiàn)main方法之后,啟動的線程稱作“主線程”,該線程負責(zé)執(zhí)行main方法。在main方法的執(zhí)行中再創(chuàng)立的線程,就稱為程序中的其它線程。如果main方法中沒有創(chuàng)立其他的線程,那么當(dāng)main方法執(zhí)行完最后一個語句,JVM就會結(jié)束Java應(yīng)用程序。如果main方法中又創(chuàng)立了其他線程,那么JVM就要在主線程和其他線程之間輪流切換,main方法即使執(zhí)行完最后的語句,JVM也不會結(jié)束程序,JVM一直要等到程序中的所有線程都結(jié)束之后,才結(jié)束Java應(yīng)用程序。8Java中創(chuàng)立線程的兩種方法Thread類的子類創(chuàng)立線程對象,子類重寫Thread類中的run()方法使用Thread類直接創(chuàng)立線程對象,但需要使用Runable接口9Thread類Thread類在Java程序中創(chuàng)立多線程的方法之一是繼承Thread類封裝了Java程序中一個線程對象需要擁有的屬性和方法從Thread類派生一個子類,并創(chuàng)立這個子類的對象,就可以產(chǎn)生一個新的線程。這個子類應(yīng)該重寫Thread類的run〔〕方法,在run方法中寫入需要在新線程中執(zhí)行的語句段。這個子類的對象需要調(diào)用start方法來啟動,新線程將自動進入run方法。原線程將同時繼續(xù)往下執(zhí)行它位于java.lang包中,因而程序開頭不用import任何包就可直接使用例子:Example9_1.java10publicclassExample9_1{publicstaticvoidmain(Stringargs[]){Lefthandleft;Righthandright;left=newLefthand();//創(chuàng)立線程right=newRighthand();left.start();right.start();for(inti=1;i<=3;i++){("我是主線程");}}}classLefthandextendsThread{publicvoidrun(){for(inti=1;i<=3;i++){("我是左手線程");}}}classRighthandextendsThread{publicvoidrun(){for(inti=1;i<=3;i++){("我是右手線程");}}}我是主線程我是主線程我是主線程我是左手線程我是左手線程我是左手線程我是右手線程我是右手線程我是右手線程11Thread類(續(xù))

在新線程中完成計算某個整數(shù)的階乘publicclassEx8_1{publicstaticvoidmain(String[]args){ System.out.println("mainthreadstarts"); FactorialThreadthread=newFactorialThread(10);

thread.start();

System.out.println("mainthreadends");}}classFactorialThreadextends

Thread{privateintnum;publicFactorialThread(intnum){this.num=num;

}

12publicvoidrun(){inti=num;intresult=1;System.out.println("newthreadstarted");while(i>0){ result=result*i; i=i-1;}System.out.println("Thefactorialof"+num+"is"+result);System.out.println("newthreadends");}}運行結(jié)果mainthreadstartsmainthreadendsnewthreadstartedThefactorialof10is3628800newthreadendsThread類(續(xù))

13結(jié)果說明main線程已經(jīng)執(zhí)行完后,新線程才執(zhí)行完main函數(shù)調(diào)用thread.start()方法啟動新線程后并不等待其run方法返回就繼續(xù)運行(執(zhí)行()),thread.run函數(shù)在一邊單獨運行,不影響原來的main函數(shù)的運行源程序修改如果啟動新線程后希望主線程多持續(xù)一會再結(jié)束,可在start語句后加上讓當(dāng)前線程〔main〕休息1毫秒的語句:try{Thread.sleep(1);}catch(Exceptione){};Thread類(續(xù))

14修改后運行結(jié)果mainthreadstartsnewthreadstaredThefactorialof10is3628800newthreadendsmainthreadends運行結(jié)果說明新線程結(jié)束后main線程才結(jié)束例子Ex8_1.javaThread類(續(xù))

——例8_1修改后運行結(jié)果15Thread類(續(xù))

——常用API函數(shù)名稱說明publicThread()構(gòu)造一個新的線程對象,默認名為Thread-n,n是從0開始遞增的整數(shù)publicThread(Runnabletarget)構(gòu)造一個新的線程對象,以一個實現(xiàn)Runnable接口的類的對象為參數(shù)。默認線程名為Thread-n,n是從0開始遞增的整數(shù)publicThread(Stringname)構(gòu)造一個新的線程對象,并同時指定線程名publicstaticThreadcurrentThread()返回當(dāng)前正在運行的線程對象publicstaticvoidyield()使當(dāng)前線程對象暫停,允許別的線程開始運行publicstaticvoidsleep(longmillis)使當(dāng)前線程暫停運行指定毫秒數(shù),但此線程并不失去已獲得的鎖旗標(biāo)。16publicvoidstart()啟動線程,JVM將調(diào)用此線程的run方法,結(jié)果是將同時運行兩個線程,當(dāng)前線程和執(zhí)行run方法的線程publicvoidrun()Thread的子類應(yīng)該重寫此方法,內(nèi)容應(yīng)為該線程應(yīng)執(zhí)行的任務(wù)。publicfinalvoidstop()停止線程運行,釋放該線程占用的對象鎖旗標(biāo)。publicvoidinterrupt()打斷此線程publicfinalvoidjoin()在當(dāng)前線程中加入調(diào)用join方法的線程A,直到線程A死亡才能繼續(xù)執(zhí)行當(dāng)前線程publicfinalvoidjoin(longmillis)在當(dāng)前線程中加入調(diào)用join方法的線程A,直到到達參數(shù)指定毫秒數(shù)或線程A死亡才能繼續(xù)執(zhí)行當(dāng)前線程Thread類(續(xù))

——常用API函數(shù)17publicfinalvoidsetPriority(intnewPriority)設(shè)置線程優(yōu)先級publicfinalvoidsetDaemon(Booleanon)設(shè)置是否為后臺線程,如果當(dāng)前運行線程均為后臺線程則JVM停止運行。這個方法必須在start()方法前使用publicfinalvoidcheckAccess()判斷當(dāng)前線程是否有權(quán)力修改調(diào)用此方法的線程publicvoidsetName(Stringname)更改本線程的名稱為指定參數(shù)publicfinalbooleanisAlive()測試線程是否處于活動狀態(tài),如果線程被啟動并且沒有死亡則返回trueThread類(續(xù))

——常用API函數(shù)18創(chuàng)立3個新線程,每個線程睡眠一段時間〔0~6秒〕,然后結(jié)束publicclassEx8_2{publicstaticvoidmain(String[]args){//創(chuàng)立并命名每個線程TestThreadthread1=newTestThread("thread1");TestThreadthread2=newTestThread("thread2");TestThreadthread3=newTestThread("thread3");("Startingthreads");thread1.start();//啟動線程1thread2.start();//啟動線程2thread3.start();//啟動線程3("Threadsstarted,mainends\n");}}Thread類(續(xù))

——例8_219classTestThreadextendsThread{privateintsleepTime;publicTestThread(Stringname){super(name);//調(diào)用父類構(gòu)造函數(shù)為線程命名

sleepTime=(int)(Math.random()*6000);

}publicvoidrun(){try{(getName()+"goingtosleepfor"+sleepTime);

Thread.sleep(sleepTime);//線程休眠

}catch(InterruptedExceptionexception){};(getName()+"finished"}}Thread類(續(xù))

——例8_220運行結(jié)果StartingthreadsThreadsstarted,mainendsthread1goingtosleepfor3519thread2goingtosleepfor1689thread3goingtosleepfor5565thread2finishedthread1finishedthread3finished說明由于線程3休眠時間最長,所以最后結(jié)束,線程2休眠時間最短,所以最先結(jié)束每次運行,都會產(chǎn)生不同的隨機休眠時間,所以結(jié)果都不相同Thread類(續(xù))

——例8_2運行結(jié)果21Runnable接口Runnable接口在編寫復(fù)雜程序時相關(guān)的類可能已經(jīng)繼承了某個基類,而Java不支持多繼承,在這種情況下,便需要通過實現(xiàn)Runnable接口來生成多線使用Thread創(chuàng)立線程對象時,通常使用的構(gòu)造方法是:Thread〔Runnabletarget〕該構(gòu)造方法中的參數(shù)是一個Runnable類型的接口,因此,在創(chuàng)立線程

對象時必須向構(gòu)造方法的參數(shù)傳遞一個實現(xiàn)Runnable接口類的實例,

該實例對象稱作所創(chuàng)線程的目標(biāo)對象.當(dāng)線程調(diào)用start方法后,一旦輪到它來享用CPU資源,目標(biāo)對象就會自動調(diào)用接口中的run方法〔接口回調(diào)〕.對于使用同一目標(biāo)對象的線程,目標(biāo)對象的成員變量自然就是這些線程的共享數(shù)據(jù)單元不同run()方法中的局部變量互不干擾。修改Ex8_1.java

例子:workspace/ThreadDemo2_2.java〔java2006/example9/ThreadDemo1_1,ThreadDemo2_2〕例子:Example9_3.javaTestThreadextendsThread{…..}TestThreadimplementsRunnable{newThread(Runnableth).start}22使用Runnable接口實現(xiàn)Ex8_1功能(使用一個目標(biāo)對象)publicclassEx8_1{publicstaticvoidmain(String[]args){System.out.println("mainthreadstarts");FactorialThreadt=newFactorialThread(10);newThread(t).start();//創(chuàng)立Thread對象System.out.println("newthreadstarted,mainthreadends");}}Runnable接口(續(xù))

——例8_1_1Runnable接口類的實例23classFactorialThreadimplementsRunnable{privateintnum;publicFactorialThread(intnum){this.num=num;

}publicvoidrun(){inti=num;intresult=1;while(i>0){ result=result*i; i=i-1;}System.out.println("Thefactorialof"+num+"is"+result);System.out.println("newthreadends");}}Runnable接口(續(xù))

——例8_324使用Runnable接口實現(xiàn)例8_2功能〔使用不同目標(biāo)對象〕publicclassEx8_4{publicstaticvoidmain(String[]args){ TestThreadthread1=newTestThread();TestThreadthread2=newTestThread();TestThreadthread3=newTestThread();("Startingthreads");

newThread(thread1,"Thread1").start();newThread(thread2,"Thread2").start();newThread(thread3,"Thread3").start();

("Threadsstarted,mainends\n");}}Runnable接口(續(xù))

——例8_4傳遞一個實現(xiàn)Runnable接口類的實例,并啟動線程25classTestThreadimplementsRunnable{privateintsleepTime;publicTestThread()

{sleepTime=(int)(Math.random()*6000);

}publicvoidrun(){try{(

Thread.currentThread().getName()+"goingtosleepfor"+sleepTime);

Thread.sleep(sleepTime);

}catch(InterruptedExceptionexception){};

(Thread.currentThread().getName()+"finished");

}}Runnable接口(續(xù))

——例8_4StartingthreadsThreadsstarted,mainendsThread2goingtosleepfor1498Thread1goingtosleepfor4544Thread3goingtosleepfor3251Thread2finishedThread3finishedThread1finished26線程間的數(shù)據(jù)共享代碼共享多個線程的執(zhí)行代碼來自同一個類的run方法時,即稱它們共享相同的代碼數(shù)據(jù)共享當(dāng)共享訪問相同的對象時,即它們共享相同的數(shù)據(jù)不同線程的run()方法中的局部變量互不干擾〔Example9_5_1.java〕使用Runnable接口可以輕松實現(xiàn)多個線程共享相同數(shù)據(jù),只要用同一個實現(xiàn)了Runnable接口的實例作為參數(shù)創(chuàng)立多個線程即可〔Ex8_5.java,p233-例9.3〕27classExample9_5_1{public

static

voidmain(Stringargs[]){

Movemove=newMove();

newThread(move,"zhangsan").start();

newThread(move,"lisi").start();}}28classMoveimplementsRunnable{

//inti=0;

public

voidrun(){inti=0;

while(i<=5){if(Thread.currentThread().getName().equals("zhangsan")){i=i+1;System.out.println(Thread.currentThread().getName()+"線程的局部變量i="+i);}

else

if(Thread.currentThread().getName().equals("lisi")){i=i+1;System.out.println(Thread.currentThread().getName()+"線程的局部變量i="+i);}

try{Thread.sleep(800);}

catch(InterruptedExceptione){}}}}29修改例8_4,只用一個Runnable類型的對象為參數(shù)創(chuàng)立3個新線程。publicclassEx8_5{publicstaticvoidmain(String[]args){ TestThreadthreadobj=newTestThread();("Startingthreads");

newThread(threadobj,"Thread1").start();newThread(threadobj,"Thread2").start();newThread(threadobj,"Thread3").start();

("Threadsstarted,mainends\n");}}線程間的數(shù)據(jù)共享(續(xù))

——例8_530classTestThreadimplementsRunnable{ privateintsleepTime; publicTestThread()

{sleepTime=(int)(Math.random()*6000);

} publicvoidrun()

{try{(Thread.currentThread().getName()+"goingtosleepfor"+ sleepTime);Thread.sleep(sleepTime);

}catch(InterruptedExceptionexception){}; (Thread.currentThread().getName()+"finished"); }}線程間的數(shù)據(jù)共享(續(xù))

——例8_531運行結(jié)果StartingthreadsThread1goingtosleepfor966Thread2goingtosleepfor966Threadsstarted,mainendsThread3goingtosleepfor966Thread1finishedThread2finishedThread3finished說明因為是用一個Runnable類型對象創(chuàng)立的3個新線程,這三個線程就共享了這個對象的私有成員sleepTime,在本次運行中,三個線程都休眠了966毫秒線程間的數(shù)據(jù)共享(續(xù))

——例8_5運行結(jié)果32publicclassEx8_6{ publicstaticvoidmain(String[]args){ SellTicketst=newSellTickets();newThread(t).start();

newThread(t).start(); newThread(t).start(); }}線程間的數(shù)據(jù)共享(實際應(yīng)用)

——例8_6用三個線程模擬三個售票口,總共出售200張票-用3個線程模仿3個售票口的售票行為-這3個線程應(yīng)該共享200張票的數(shù)據(jù)33classSellTicketsimplementsRunnable{ privateinttickets=200;

publicvoidrun(){

while(tickets>0){ (Thread.currentThread().getName()+ "issellingticket"+tickets--); } }}線程間的數(shù)據(jù)共享(續(xù))

——例8_634運行結(jié)果選最后幾行如下Thread-2issellingticket6Thread-1issellingticket5Thread-0issellingticket4Thread-2issellingticket3Thread-1issellingticket2Thread-0issellingticket1說明在這個例子中,創(chuàng)立了3個線程,每個線程調(diào)用的是同一個SellTickets對象中的run()方法,訪問的是同一個對象中的變量〔tickets〕如果是通過創(chuàng)立Thread類的子類來模擬售票過程,再創(chuàng)立3個新線程,那么每個線程都會有各自的方法和變量,雖然方法是相同的,但變量卻是各有200張票,因而結(jié)果將會是各賣出200張票,和原意就不符了線程間的數(shù)據(jù)共享(續(xù))

——例8_6運行結(jié)果35publicvoidstart()啟動線程,JVM將調(diào)用此線程的run方法,結(jié)果是將同時運行兩個線程,當(dāng)前線程和執(zhí)行run方法的線程publicvoidrun()Thread的子類應(yīng)該重寫此方法,內(nèi)容應(yīng)為該線程應(yīng)執(zhí)行的任務(wù)。publicfinalvoidstop()停止線程運行,釋放該線程占用的對象鎖旗標(biāo)。publicvoidinterrupt()打斷此線程publicfinalvoidjoin()在當(dāng)前線程中加入調(diào)用join方法的線程A,直到線程A死亡才能繼續(xù)執(zhí)行當(dāng)前線程publicfinalvoidjoin(longmillis)在當(dāng)前線程中加入調(diào)用join方法的線程A,直到到達參數(shù)指定毫秒數(shù)或線程A死亡才能繼續(xù)執(zhí)行當(dāng)前線程Thread類(續(xù))

——常用API函數(shù)36interrupt()方法舉例publicclassExample9_9{publicstaticvoidmain(Stringargs[]){Aa=newA();();();}}classAimplementsRunnable{Threadstudent,teacher;A(){teacher=newThread(this);student=newThread(this);teacher.setName("王教授");student.setName("張三");}37

publicvoidrun(){if(Thread.currentThread()==student){try{System.out.println(student.getName()+"正在睡覺,不聽課");Thread.sleep(1000*60*60);}catch(InterruptedExceptione){System.out.println(student.getName()+"被老師叫醒了");}System.out.println(student.getName()+"開始聽課");}38

elseif(Thread.currentThread()==teacher){for(inti=1;i<=3;i++){("上課!");try{Thread.sleep(500);}catch(InterruptedExceptione){}}

errupt();//吵醒student}}}interrupt()方法使student線程發(fā)生InterruptException,從而結(jié)束休眠39GUI線程Example9_1140多線程的同步控制有時線程之間彼此不獨立、需要同步(相互配合)線程間的互斥同時運行的幾個線程需要共享一個〔些〕數(shù)據(jù)一個線程對共享的數(shù)據(jù)進行操作時,不允許其他線程打斷它,否那么會破壞數(shù)據(jù)的完整性。即被多個線程共享的數(shù)據(jù),在某一時刻只允許一個線程對其進行操作“生產(chǎn)者/消費者”問題〔工資管理員/雇員〕生產(chǎn)者產(chǎn)生數(shù)據(jù),消費者消費數(shù)據(jù),具體來說,假設(shè)有一個Java應(yīng)用程序,其中有一個線程負責(zé)往數(shù)據(jù)區(qū)寫數(shù)據(jù),另一個線程從同一數(shù)據(jù)區(qū)中讀數(shù)據(jù),兩個線程可以并行執(zhí)行〔類似于流水線上的兩道工序〕如果數(shù)據(jù)區(qū)已滿,,生產(chǎn)者要等消費者取走一些數(shù)據(jù)后才能再放;而當(dāng)數(shù)據(jù)區(qū)沒有數(shù)據(jù)時,消費者要等生產(chǎn)者放入一些數(shù)據(jù)后再取41線程同步的概念,包括互斥和協(xié)作互斥:許多線程在同一個共享數(shù)據(jù)上操作而互不干擾,同一時刻只能有一個線程訪問該共享數(shù)據(jù)。因此有些方法或程序段在同一時刻只能被一個線程執(zhí)行,稱之為監(jiān)視區(qū)〔臨界區(qū)〕協(xié)作:多個線程可以有條件地同時操作共享數(shù)據(jù)。執(zhí)行監(jiān)視區(qū)代碼的線程在條件滿足的情況下可以允許其它線程進入監(jiān)視區(qū)〔臨界區(qū)〕多線程的同步控制(續(xù))

——線程同步(Synchronization)42

ProducerandConsumerHolderProducerInput-Dataq0q0…qnq1ProducerInput-Dataq1ConsumerOutputDataqn+1ProducerInput-Dataqn+143synchronized——線程同步關(guān)鍵字把需要修改數(shù)據(jù)的方法用關(guān)鍵字synchronized來修飾,用于指定需要同步的代碼段或方法,也就是監(jiān)視區(qū)當(dāng)一個線程A使用一個synchronized修飾的方法時,其他線程想使用這個方法時就必須等待,直到線程A使用完該方法〔除非線程A使用wait主動讓出CUP資源〕.當(dāng)被synchronized限定的代碼段執(zhí)行完,就釋放鎖旗標(biāo)〔信號量〕例子:Example9_13.java多線程的同步控制(續(xù))

——synchronized關(guān)鍵字44線程間的通信為了更有效地協(xié)調(diào)不同線程的工作,需要在線程間建立溝通渠道,通過線程間的“對話”來解決線程間的同步問題類的一些方法為線程間的通訊提供了有效手段一個線程在使用的同步方法中時,可能根據(jù)問題的需要,必須使用wait()(掛起)方法使本線程等待,暫時讓出CPU的使用權(quán),并允許其它線程使用這個同步方法。其它線程如果在使用這個同步方法時如果不需要等待,那么它用完這個同步方法的同時,應(yīng)當(dāng)執(zhí)行notify(),notifyAll()〔恢復(fù)〕方法通知所有的由于使用這個同步方法而處于等待的線程結(jié)束等待。例子:Example9_14.java,Ex8_8.java,Ex8_9.java45線程的優(yōu)先級每個Java線程都有一個優(yōu)先級,其范圍都在1和10之間。默認情況下,每個線程的優(yōu)先級都設(shè)置為5在線程A運行過程中創(chuàng)立的新的線程對象B,初始狀態(tài)具有和線程A相同的優(yōu)先級如果A是個后臺線程,那么B也是個后臺線程可在線程創(chuàng)立之后的任何時候,通過setPriority(intpriority)方法改變其原來的優(yōu)先級線程的優(yōu)先級(續(xù))46基于線程優(yōu)先級的線程調(diào)度具有較高優(yōu)先級的線程比優(yōu)先級較低的線程優(yōu)先執(zhí)行對具有相同優(yōu)先級的線程,Java的處理是隨機的底層操作系統(tǒng)支持的優(yōu)先級可能要少于10個,這樣會造成一些混亂。因此,只能將優(yōu)先級作為一種很粗略的工具使用。最后的控制可以通過明智地使用yield()函數(shù)來完成我們只能基于效率的考慮來使用線程優(yōu)先級,而不能依靠線程優(yōu)先級來保證算法的正確性線程的優(yōu)先級(續(xù))47假設(shè)某線程正在運行,那么只有出現(xiàn)以下情況之一,才會使其暫停運行一個具有更高優(yōu)先級的線程變?yōu)榫途w狀態(tài)〔Ready〕;由于輸入/輸出〔或其他一些原因〕、調(diào)用sleep、wait、yield方法使其發(fā)生阻塞;對于支持時間分片的系統(tǒng),時間片的時間期滿線程的優(yōu)先級(續(xù))48創(chuàng)立兩個具有不同優(yōu)先級的線程,都從1遞增到400000,每增加50000顯示一次publicclassEx8_13{publicstaticvoidmain(String[]args){ TestThread[]runners=newTestThread[2];for(inti=0;i<2;i++)runners[i]=newTestThread(i);runners[0].setPriority(2);//設(shè)置第一個線程優(yōu)先級為2runners[1].setPriority(3);//設(shè)置第二個線程優(yōu)先級為3for(inti=0;i<2;i++)runners[i].start();}}線程的優(yōu)先級(續(xù))

——例8_1349classTestThreadextendsThread{ privateinttick=1; privateintnum; publicTestThread(inti){this.num=i; } publicvoidrun(){ while(tick<400000){tick++;if((tick%50000)==0){//每隔5000進行顯示

("Thread#"+num+",tick="+tick);yield();//放棄執(zhí)行權(quán)

}}} }線程的優(yōu)先級(續(xù))

——例8_1350線程的優(yōu)先級(續(xù))

——例8_13運行結(jié)果運行結(jié)果Thread#1,tick=50000Thread#1,tick=100000Thread#1,tick=150000Thread#1,tick=200000Thread#1,tick=250000Thread#1,tick=300000Thread#1,tick=350000Thread#1,tick=400000Thread#0,tick=50000Thread#0,tick=100000Thread#0,tick=150000Thread#0,tick=200000Thread#0,tick=250000Thread#0,tick=300000Thread#0,tick=350000Thread#0,tick=400000結(jié)果說明具有較高優(yōu)先級的線程1一直運行到結(jié)束,具有較低優(yōu)先級的線程0才開始運行雖然具有較高優(yōu)先級的線程1調(diào)用了yield方法放棄CPU資源,允許線程0進行爭奪,但馬上又被線程1搶奪了回去,所以有沒有yield方法都沒什么區(qū)別51如果在yield方法后增加一行sleep語句,讓線程1暫時放棄一下在CPU上的運行,哪怕是1毫秒,那么線程0也可以有時機被調(diào)度。修改后的run方法如下publicvoidrun(){ while(tick<400000){tick++;if((tick%50000)==0){("Thread#"+num+",tick="+tick);yield();try{sleep(1);}catch(Exceptione){};}}} 線程的優(yōu)先級(續(xù))

——例8_13修改52線程的優(yōu)先級(續(xù))

——例8_13修改后運行結(jié)果運行結(jié)果Thread#1,tick=50000Thread#1,tick=100000Thread#1,tick=150000Thread#1,tick=200000Thread#0,tick=50000Thread#1,tick=250000Thread#1,tick=300000Thread#0,tick=100000Thread#1,tick=350000Thread#1,tick=400000Thread#0,tick=150000Thread#0,tick=200000Thread#0,tick=250000Thread#0,tick=300000Thread#0,tick=350000Thread#0,tick=400000說明具有較低優(yōu)先權(quán)的線程0在線程1沒有執(zhí)行完畢前也獲得了一局部執(zhí)行,但線程1還是優(yōu)先完成了執(zhí)行通常,我們在一個線程內(nèi)部插入yield()語句,這個方法會使正在運行的線程暫時放棄執(zhí)行,這是具有同樣優(yōu)先級的線程就有時機獲得調(diào)度開始運行,但較低優(yōu)先級的線程仍將被忽略不參加調(diào)度53本章小結(jié)本章內(nèi)容線程的根底知識線程的生命周期線程的優(yōu)先級本章要求了解線程的概念學(xué)會如何通過Thread類和Runnable接口創(chuàng)立線程,如何實現(xiàn)多線程的資源共享和通信,及如何控制線程的生命掌握線程同步的方法理解線程優(yōu)先級的概念,以及基于優(yōu)先級的線程調(diào)度54/holderholdingergersclassHoldInteger{ intshareInt=-1; booleanmoreData=true; publicvoidsetSharedInt(intval){shareInt=val;} publicintgetSharedInt(){returnshareInt;} publicvoidsetMoreData(booleanb){moreData=b;} publicbooleanhasMoreData(){returnmoreData;}}55//producerproducesintegersandputthemintoholderclassProducIntegerextendsThread{ HoldIntegerpHold; publicProducInteger(HoldIntegerh) { pHold=h; } publicvoidrun() { for(intcount=0;count<10;count++){

//sleepforrandominterval try{ Thread.sleep((int)(Math.random()*300)); } catch(InterruptedExceptione){ System.err.println(e.toString()); } pHold.setSharedInt(count); System.out.println("ProdecersetshareIntto"+count); }//setMoreDatatofalsewhencount<10.Itmeansholderisfull pHold.setMoreData(false); }}56//consumergetintegersfromholderclassConsumeIntegerextendsThread{ HoldIntegercHold; publicConsumeInteger(HoldIntegerh) { cHold=h; } publicvoidrun() { intval; while(cHold.hasMoreData()){ //sleepforrandominterval try{ Thread.sleep((int)(Math.random()*3000)); } catch(InterruptedExceptione){ System.err.println(e.toString());} val=cHold.getSharedInt();System.out.println("Consumerretrieved"+val);} }}57publicclasssynDemo{publicstaticvoidmain(Stringargs[]){HoldIntegerh=newHoldInteger();ProducIntegerp=newProducInteger(h);ConsumeIntegerc=newConsumeInteger(h);p.start();c.start();}}返回58運行結(jié)果ProdecersetshareIntto0ProdecersetshareIntto1ProdecersetshareIntto2ProdecersetshareIntto3ProdecersetshareIntto4Consumerretrieved4ProdecersetshareIntto5ProdecersetshareIntto6ProdecersetshareIntto7ProdecersetshareIntto8ProdecersetshareIntto9Consumerretrieved9返回59掛起有時候兩個線程并不是同步的,即不涉及都需要調(diào)用一個同步方法,但線程也可能需要暫時的掛起。所謂掛起一個線程就是讓線程暫時讓出CPU的使用權(quán)限,暫時停止執(zhí)行,但停止執(zhí)行的持續(xù)時間不確定,因此不能使用sleep方法暫停線程。掛起一個線程需使用wait方法,即讓準(zhǔn)備掛起的線程調(diào)用wait方法,主動讓出CPU的使用權(quán)限.恢復(fù)

為了恢復(fù)該線程,其它線程在占有CUP資源期間,讓掛起的線程的目標(biāo)對象執(zhí)行notifyAll()方法,使得掛起的線程繼續(xù)執(zhí)行;如果線程沒有目標(biāo)對象,為了恢復(fù)該線程,其它線程在占有CUP資源期間,讓掛起的線程調(diào)用notifyAll()方法,使掛起的線程繼續(xù)執(zhí)行。返回60Example9_13.java局部代碼publicsynchronizedvoid存取(intnumber)//存取方法{if(Thread.curre

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論