![線程和多線程98_第1頁(yè)](http://file4.renrendoc.com/view/6e908d2a055d3a163ff3168151e3ee9c/6e908d2a055d3a163ff3168151e3ee9c1.gif)
![線程和多線程98_第2頁(yè)](http://file4.renrendoc.com/view/6e908d2a055d3a163ff3168151e3ee9c/6e908d2a055d3a163ff3168151e3ee9c2.gif)
![線程和多線程98_第3頁(yè)](http://file4.renrendoc.com/view/6e908d2a055d3a163ff3168151e3ee9c/6e908d2a055d3a163ff3168151e3ee9c3.gif)
![線程和多線程98_第4頁(yè)](http://file4.renrendoc.com/view/6e908d2a055d3a163ff3168151e3ee9c/6e908d2a055d3a163ff3168151e3ee9c4.gif)
![線程和多線程98_第5頁(yè)](http://file4.renrendoc.com/view/6e908d2a055d3a163ff3168151e3ee9c/6e908d2a055d3a163ff3168151e3ee9c5.gif)
版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、第13章 線 程線程和多線程線程的概念在程序開(kāi)始投入運(yùn)行時(shí),系統(tǒng)從程序入口開(kāi)始按語(yǔ)句的順序(其中包括順序、分支和循環(huán))完成相應(yīng)指令直至結(jié)尾,從出口退出,同時(shí)整個(gè)程序結(jié)束。這樣的語(yǔ)句結(jié)構(gòu)稱(chēng)之為進(jìn)程,或者說(shuō)進(jìn)程就是程序在處理機(jī)中的一次運(yùn)行。線程的概念一個(gè)進(jìn)程既包括其所要執(zhí)行的指令,也包括了執(zhí)行指令所需的任何系統(tǒng)資源,如CPU、內(nèi)存空間、I/O端口等,不同進(jìn)程所占用的系統(tǒng)資源相對(duì)獨(dú)立。線程的概念目前所流行的操作系統(tǒng)中,大局部都是支持多任務(wù)的(如Windows 3.X,Windows NT,Windows 95,OS/2及UNIX的各個(gè)版本),這實(shí)際就是一種多進(jìn)程的概念每一個(gè)任務(wù)就是一個(gè)進(jìn)程。線程的概
2、念線程是比進(jìn)程單位更小的執(zhí)行單位,在形式上同進(jìn)程十分相似都是用一個(gè)順序執(zhí)行的語(yǔ)句序列來(lái)完成特定的功能。線程沒(méi)有入口,也沒(méi)有出口,因此其自身不能自動(dòng)運(yùn)行,而必須棲身于某一進(jìn)程之中,由進(jìn)程觸發(fā)執(zhí)行。線程的概念在系統(tǒng)資源的使用上,屬于同一進(jìn)程的所有線程共享該進(jìn)程的系統(tǒng)資源,但是線程之間切換的速度比進(jìn)程切換要快得多。線程的概念從微觀上講,一個(gè)時(shí)間里只能有一個(gè)作業(yè)被執(zhí)行,在宏觀上可使多個(gè)作業(yè)被同時(shí)執(zhí)行,即等同于要讓多臺(tái)計(jì)算機(jī)同時(shí)工作,使系統(tǒng)資源特別是CPU的利用率得到提高,從而提高了整個(gè)程序的執(zhí)行效率。線程的概念為了到達(dá)多線程的效果,Java語(yǔ)言把線程或執(zhí)行環(huán)境execution context當(dāng)作一種
3、擁有自己的程序代碼和數(shù)據(jù)的對(duì)CPU的封裝單位,由虛擬機(jī)提供控制。Java類(lèi)庫(kù)中的類(lèi)java.lang.Thread允許創(chuàng)立并控制所創(chuàng)立的線程。線程的結(jié)構(gòu)以下圖是線程運(yùn)行機(jī)制示意圖:CPUCodeData線程的結(jié)構(gòu)線程包含三個(gè)主要局部:虛擬CPU本身,CPU執(zhí)行的代碼,代碼操作的數(shù)據(jù)。線程的結(jié)構(gòu)在Java中,虛擬CPU表達(dá)于Thread類(lèi)中。當(dāng)一個(gè)線程被構(gòu)造時(shí),它由構(gòu)造方法參數(shù)、執(zhí)行代碼、操作數(shù)據(jù)來(lái)初始化。創(chuàng)立線程一繼承Thread類(lèi)將一個(gè)類(lèi)定義為T(mén)hread的子類(lèi),那么這個(gè)類(lèi)就可以用來(lái)表示線程。應(yīng)用這種形式的構(gòu)造方法創(chuàng)立線程對(duì)象時(shí)不用給出任何參數(shù)。這個(gè)類(lèi)中有一個(gè)至關(guān)重要的方法public vo
4、id run(),這個(gè)方法稱(chēng)為線程體,它是整個(gè)線程的核心,線程所要完成任務(wù)的代碼都定義在線程體中,實(shí)際上不同功能的線程之間的區(qū)別就在于它們線程體的不同。程序13-1public class myThread extends Threadpublic void run()while(running)/ 執(zhí)行假設(shè)干操作sleep(100);public static void main(String args)Thread t = new myThread();/ 執(zhí)行假設(shè)干操作創(chuàng)立線程二實(shí)現(xiàn)Runnable接口Runnable是Java中用以實(shí)現(xiàn)線程的接口,從根本上講,任何實(shí)現(xiàn)線程功能的類(lèi)都必須
5、實(shí)現(xiàn)該接口。Runnable接口中只定義了一個(gè)方法就是run()方法,也就是線程體。創(chuàng)立線程二實(shí)現(xiàn)Runnable接口Thread第二種構(gòu)造方法中包含有一個(gè)Runnable實(shí)例的參數(shù),這就是說(shuō),必須定義一個(gè)實(shí)現(xiàn)Runnable接口的類(lèi)并產(chǎn)生一個(gè)該類(lèi)的實(shí)例,對(duì)該實(shí)例的引用就是適合于這個(gè)構(gòu)造方法的參數(shù)。程序 13-2public class xyz implements Runnableint i;public void run()while (true) System.out.println(Hello +i+);程序 13-2可以構(gòu)造一個(gè)線程如下:Runnable r = new xyz();
6、Thread t = new Thread(r);線程運(yùn)行環(huán)境CPUCodeDataThread txyz rclass xyz線程關(guān)于兩種創(chuàng)立線程方法的討論1. 適用于采用實(shí)現(xiàn)Runnable接口方法的情況因?yàn)镴ava只允許單繼承,如果一個(gè)類(lèi)已經(jīng)繼承了Thread,就不能再繼承其他類(lèi)。比方對(duì)于Applet程序,由于必須繼承了java. applet.Applet,因此就只能采取這種實(shí)現(xiàn)接口的方法。由于某些原因而幾次被迫采用實(shí)現(xiàn)Runnable接口的方法,可能會(huì)出于保持程序風(fēng)格的一貫性而繼續(xù)使用這種方法。關(guān)于兩種創(chuàng)立線程方法的討論2. 適用于采用繼承Thread方法的情況當(dāng)一個(gè)run()方法置
7、于Thread類(lèi)的子類(lèi)中時(shí),this實(shí)際上引用的是控制當(dāng)前運(yùn)行系統(tǒng) 的Thread實(shí)例,所以,代碼不必寫(xiě)得繁瑣:Thread.currentThread().suspend();可簡(jiǎn)單地寫(xiě)為:suspend();線程的啟動(dòng)必須通過(guò)方法start()來(lái)啟動(dòng)線程,start()方法也在Thread類(lèi)中。線程的調(diào)度在一臺(tái)只具有一個(gè)CPU的機(jī)器上,CPU在同一時(shí)間只能分配給一個(gè)線程做一件事。當(dāng)有多于一個(gè)的線程工作時(shí),在Java中,線程調(diào)度通常是搶占式,而不是時(shí)間片式。搶占式調(diào)度是指可能有多個(gè)線程準(zhǔn)備運(yùn)行,但只有一個(gè)在真正運(yùn)行。線程的調(diào)度一個(gè)線程獲得執(zhí)行權(quán),這個(gè)線程將持續(xù)運(yùn)行下去,直到它運(yùn)行結(jié)束或因?yàn)槟?/p>
8、種原因而阻塞,或者有另一個(gè)高優(yōu)先級(jí)線程就緒這種情況稱(chēng)為低優(yōu)先級(jí)線程被高優(yōu)先級(jí)線程所搶占。線程的調(diào)度一個(gè)線程被阻塞的原因:因?yàn)閳?zhí)行了Thread.sleep()調(diào)用,成心讓它暫停一段時(shí)間;因?yàn)樾枰却粋€(gè)較慢的外部設(shè)備,例如磁盤(pán)或用戶(hù)。線程的調(diào)度所有被阻塞的線程按次序排列,組成一個(gè)阻塞隊(duì)列。所有就緒但沒(méi)有運(yùn)行的線程那么根據(jù)其優(yōu)先級(jí)排入一個(gè)就緒隊(duì)列。線程的調(diào)度當(dāng)CPU空閑時(shí),如果就緒隊(duì)列不空,就緒隊(duì)列中第一個(gè)具有最高優(yōu)先級(jí)的線程將運(yùn)行。當(dāng)一個(gè)線程被搶占而停止運(yùn)行時(shí),它的運(yùn)行態(tài)被改變并放到就緒隊(duì)列的隊(duì)尾;線程的調(diào)度一個(gè)被阻塞可能因?yàn)樗呋虻却齀/O設(shè)備的線程就緒后通常也放到就緒隊(duì)列的隊(duì)尾。程序 13
9、-3public class xyz implements Runnablepublic void run()while(true) / 執(zhí)行假設(shè)干操作/ 給其他線程運(yùn)行的時(shí)機(jī)tryThread.sleep(10);catch(InterruptedException e)/ 該線程為其他線程所中斷程序13-3sleep()是類(lèi)Thread中的靜態(tài)方法,因此可以通過(guò)Thread.sleep(x)直接引用。參數(shù)x指定了線程在再次啟動(dòng)前必須休眠的最小時(shí)間,是以毫秒為單位的。同時(shí)該方法可能引發(fā)中斷異常InterruptedException,因此要進(jìn)行捕獲和處理。程序13-3除sleep()方法以外
10、,類(lèi)Thread中的另一個(gè)方法yield()可以給其他同等優(yōu)先級(jí)線程一個(gè)運(yùn)行的時(shí)機(jī)。如果在就緒隊(duì)列中有其他同優(yōu)先級(jí)的線程,yield()把調(diào)用者放入就緒隊(duì)列尾,并允許其他線程運(yùn)行;如果沒(méi)有這樣的線程,那么yield()不做任何工作。程序13-3sleep()調(diào)用允許低優(yōu)先級(jí)進(jìn)程運(yùn)行,而yield()方法只給同優(yōu)先級(jí)進(jìn)程以運(yùn)行時(shí)機(jī)。線程的根本控制結(jié)束線程當(dāng)一個(gè)線程從run()方法的結(jié)尾處返回時(shí),它自動(dòng)消亡并不能再被運(yùn)行,可以將其理解為自然死亡;利用stop()方法強(qiáng)制停止,可以將其理解為強(qiáng)迫死亡,這種方法必須用于Thread類(lèi)的特定實(shí)例中。程序 13-4public class xyz impl
11、ements Runnable / 執(zhí)行線程的主要操作public class ThreadTestpublic static void main(String args)Runnable r = new xyz();Threadt = new Thread(r);t.start();/ 進(jìn)行其他操作if (time_to_kill)t.stop();程序 13-5可以利用Thread類(lèi)中的靜態(tài)方法currentThread()來(lái)引用正在運(yùn)行的線程public class xyz implements Runnablepublic void run()while(true) / 執(zhí)行線程的主要
12、操作if (time_to_die) Thread.currentThread().stop();檢查線程可以利用方法isAlive()來(lái)獲取一個(gè)線程的活動(dòng)狀態(tài)?;顒?dòng)狀態(tài)不意味著這個(gè)線程正在執(zhí)行,而只說(shuō)明這個(gè)線程已被啟動(dòng),并且既沒(méi)有運(yùn)行stop(),也尚未運(yùn)行完方法run()。掛起線程有幾種方法可以用來(lái)暫停一個(gè)線程的運(yùn)行。在掛起之后,必須重新喚醒線程進(jìn)入運(yùn)行。掛起線程的方法1. sleep()它用于暫時(shí)停止一個(gè)線程的執(zhí)行。線程不是休眠期滿后就立刻被喚醒。重新調(diào)度只在以下幾種情況下才會(huì)發(fā)生: 被喚醒的線程具有更高的優(yōu)先級(jí)。 正在執(zhí)行的線程因?yàn)槠渌虮蛔枞?程序處于支持時(shí)間片的系統(tǒng)中。掛起線程
13、的方法2. suspend()和resume()強(qiáng)制掛起線程,而不指定休眠時(shí)間,由其他線程負(fù)責(zé)喚醒其繼續(xù)執(zhí)行。線程中有一對(duì)方法用于完成此功能,這就是suspend()和resume()。程序13-6class xyz implements Runnablepublic void run()/ 執(zhí)行線程的主要操作/ 暫停線程運(yùn)行Thread.currnetThread().suspend();/ 繼續(xù)運(yùn)行程序 13-6class Usexyzpublic static void main(String args)Runnable r = new xyz();Thread t = new Thre
14、ad(r);t.start();/* 暫停當(dāng)前線程運(yùn)行,以使xyz的實(shí)例得以運(yùn)行*/Thread.sleep(1000);/* xyz實(shí)例被suspend()方法暫停,將控制權(quán)返還給主線程,并由主線程重新喚醒線程t*/t.resume();Thread.yield();程序13-6線程t在運(yùn)行到suspend()以后被強(qiáng)制掛起,暫停運(yùn)行,直到主線程調(diào)用t.resume()時(shí)才被重新喚醒。一個(gè)線程可以被任何一條語(yǔ)句代碼所掛起,只要它具有該線程的操作權(quán),即引用它的變量。一個(gè)線程只能被不同于它自身的線程所喚醒。掛起線程的方法3. join()方法join()將引起現(xiàn)行線程等待,直至方法join所調(diào)用
15、的線程結(jié)束。程序13-7public void timeout()/ 暫停該線程,等候其他線程(tt)結(jié)束tt.join();/ 其他線程結(jié)束后,繼續(xù)進(jìn)行該線程 程序13-7說(shuō)明這樣,在執(zhí)行方法timeout()以后,現(xiàn)行的線程將被阻塞,直到tt運(yùn)行結(jié)束。join()方法在調(diào)用時(shí)也可以使用一個(gè)以毫秒計(jì)的時(shí)間值:void join(long timeout);此時(shí)join方法將掛起現(xiàn)行線程timeout毫秒,或直到調(diào)用的線程結(jié)束,實(shí)際掛起時(shí)間以二者中時(shí)間較少的為準(zhǔn)。同步問(wèn)題class Stackint idx = 0;char data = new char6;public void push(
16、char c)dataidx=c;idx +;public char pop()idx -;return dataidx;問(wèn)題的提出現(xiàn)在設(shè)想有兩個(gè)線程都具有對(duì)這個(gè)類(lèi)的同一個(gè)對(duì)象的引用,一個(gè)線程正在把數(shù)據(jù)推入棧中,而另一個(gè)與這個(gè)線程獨(dú)立的線程,正在彈出棧中元素。問(wèn)題的提出問(wèn)題:假設(shè)線程a負(fù)責(zé)參加字符,線程b負(fù)責(zé)移出字符。線程a剛剛參加了一個(gè)字符,但是尚未遞增索引值,由于某種原因,恰恰這時(shí)它被搶占了。那么此時(shí)該對(duì)象代表的數(shù)據(jù)模式將出現(xiàn)錯(cuò)誤。buffer | p | q | r | | | |idx=2問(wèn)題的提出如果線程a被及時(shí)喚醒,還沒(méi)有什么危險(xiǎn),但是如果此時(shí)線程b正在等待移出一個(gè)字符,當(dāng)線程a處
17、于等待狀態(tài)時(shí),線程b就得到了運(yùn)行時(shí)機(jī)。這樣,在進(jìn)入方法pop()時(shí),數(shù)據(jù)狀態(tài)已經(jīng)是錯(cuò)誤的。pop()方法將繼續(xù)遞減索引值:buffer | p | q | r | | | |idx=1 問(wèn)題的提出如果線程a繼續(xù)運(yùn)行將得到什么結(jié)果:線程a從push()方法中被打斷的地方繼續(xù)運(yùn)行,遞增了索引值,因此有:buffer | p | q | r | | | |inx=2將再也讀不到字母“r了。問(wèn)題的提出可以選擇的一種解決方法是禁止線程a在完成代碼關(guān)鍵局部時(shí)被切換。另一種方法,也是Java采用的方法,就是提供一個(gè)特殊的鎖定標(biāo)志來(lái)處理數(shù)據(jù)。對(duì)象的鎖定標(biāo)志Java可以為每一個(gè)對(duì)象的實(shí)例配有一個(gè)標(biāo)志,這個(gè)標(biāo)志稱(chēng)
18、做“鎖定標(biāo)志。關(guān)鍵字synchronized提供了操作這個(gè)標(biāo)志的方法。程序 13-9class stackint idx = 0;char data = new char6;public void push(char c)synchronized (this)dataidx=c;idx +;.程序13-10public char pop()synchronized (this)idx -;return dataidx;對(duì)象的鎖定標(biāo)志以下圖是線程鎖定標(biāo)志使用示意圖:線程1.因等待同步資源而掛起的線程隊(duì)列對(duì)象的鎖定標(biāo)志當(dāng)持有鎖定標(biāo)志的線程運(yùn)行完synchronized()調(diào)用包含的程序塊后,這個(gè)標(biāo)
19、志將會(huì)被自動(dòng)返還。Java保證了該標(biāo)志通常能夠被正確地返還,即使被同步的程序塊產(chǎn)生了一個(gè)異常,或者某個(gè)循環(huán)中斷跳出了該程序塊,這個(gè)標(biāo)志也能被正確返還。對(duì)象的鎖定標(biāo)志如果一個(gè)線程兩次調(diào)用了同一個(gè)對(duì)象,在退出最外層后這個(gè)標(biāo)志也將被正確釋放,而在退出內(nèi)層時(shí)那么不會(huì)執(zhí)行釋放。這些規(guī)那么使得同步程序塊的使用比其他系統(tǒng)中等同的操作,如信號(hào)燈的管理,要簡(jiǎn)單得多。同步方法synchronized()語(yǔ)句的標(biāo)準(zhǔn)寫(xiě)法為:public void push(char c)synchronized(this)同步方法synchronized()語(yǔ)句的參數(shù)必須是this。Java語(yǔ)言允許使用下面這種簡(jiǎn)潔的寫(xiě)法:publi
20、c synchronized void push(char c)同步方法區(qū)別:如果把synchronized用做方法的修飾字,那么整個(gè)方法都將稱(chēng)為同步塊,這可能會(huì)使持有鎖定標(biāo)記的時(shí)間比實(shí)際需要的時(shí)間要長(zhǎng),從而降低效率。使用前一種方法來(lái)標(biāo)記可以提醒用戶(hù)同步在發(fā)生,這在防止死鎖時(shí)非常重要。死鎖在多線程競(jìng)爭(zhēng)使用多資源的程序中,有可能出現(xiàn)死鎖的情況。這種情況發(fā)生在一個(gè)線程等待另一個(gè)線程所持有的鎖,而那個(gè)線程又在等待第一個(gè)線程持有的鎖的時(shí)候。死鎖每個(gè)線程都不能繼續(xù)運(yùn)行,除非另一線程運(yùn)行完同步程序塊。因?yàn)槟膫€(gè)線程都不能繼續(xù)運(yùn)行,所以哪個(gè)線程都無(wú)法運(yùn)行完同步程序塊。死鎖A.monitorThread xSy
21、nchronizedA.methoda()SynchronizedA.methodb()B.monitorThread ySynchronizedB.methoda()SynchronizedB.methodb()locked程序13-11class classA public classB b;synchronized void methoda() String name = Thread.currentThread().getName();System.out.println( name +“entered classA.methoda. );try Thread.sleep( 1000
22、); catch ( InterruptedException e ) System.out.println( name + trying to call classB.methodb() );b.methodb();synchronized void methodb() System.out.println( inside classB.mothedb() );class classB public classA a;synchronized void methoda() String name = Thread.currentThread().getName();System.out.pr
23、intln( name + entered classB.methoda. );try Thread.sleep( 1000 ); catch ( InterruptedException e ) System.out.println( name + trying to call classA.methodb() );a.methodb();synchronized void methodb() System.out.println( inside classB.mothedb() );class DeadLock implements RunnableclassA a = new class
24、A();classB b = new classB();DeadLock()Thread.currentThread().setName( MainThread );a.b = b;b.a = a;new Thread( this ).start();a.methoda();System.out.println( back to main thread );public void run()Thread.currentThread().setName( RacingThread );b.methoda();System.out.println( back to racing thread );
25、public static void main( String args )new DeadLock();程序 13-11如果運(yùn)行該程序就會(huì)發(fā)現(xiàn)在出現(xiàn)上述信息后發(fā)生死鎖的情況。Java既不監(jiān)測(cè)也不采取方法防止這種狀態(tài),因此保證死鎖狀態(tài)不會(huì)發(fā)生就成了程序員的職責(zé)。死鎖一個(gè)防止死鎖發(fā)生的方法是:如果有多個(gè)對(duì)象要被同步,對(duì)于獲得這些鎖的順序作一個(gè)綜合決定,并在整個(gè)程序中遵循這個(gè)順序。線程交互wait()和notify()多個(gè)線程常常被創(chuàng)立用來(lái)完成不相關(guān)的任務(wù),而線程之間有一些交互。問(wèn)題的提出為什么兩個(gè)線程可能需要交互呢?簡(jiǎn)單的例子:有兩個(gè)人,一個(gè)在刷盤(pán)子,另一個(gè)在烘干。這兩個(gè)人各自代表一個(gè)線程,他們
26、之間有一個(gè)共享的對(duì)象碗櫥。每個(gè)人都各司其職,顯然,碗櫥上有刷好的盤(pán)子時(shí),烘干的人才能開(kāi)始工作;而如果刷盤(pán)子的人刷得太快,刷好的盤(pán)子占滿了碗櫥時(shí),他就不能再繼續(xù)工作了,而要等到碗櫥上有空位置才行。解決方法Java提供了一種建立在對(duì)象實(shí)例之上的交互方法。Java中的每個(gè)對(duì)象實(shí)例都有兩個(gè)線程隊(duì)列和它相連。第一個(gè)用來(lái)排列等待鎖定標(biāo)志的線程第二個(gè)那么用來(lái)實(shí)現(xiàn)wait()和notify()的交互機(jī)制。解決方法類(lèi)java.lang.Object中定義了三個(gè)方法:wait(),notify() ,notifyAll(),解決方法wait()和notify()線程a代表刷盤(pán)子,線程b代表烘干,它們都有對(duì)對(duì)象dr
27、ainingBoard的訪問(wèn)權(quán)。假設(shè)線程b烘干線程,想要進(jìn)行烘干工作,而此時(shí)碗櫥是空的,那么應(yīng)表示如下: if (drainingBoard.isEmpty() drainingBoard.wait();解決方法當(dāng)線程b執(zhí)行了wait()調(diào)用后,它不可再執(zhí)行,并參加到對(duì)象drainingBorad的等待隊(duì)列中。在有線程將它從這個(gè)隊(duì)列中釋放之前,它不能再次運(yùn)行。解決方法烘干線程怎樣才能重新運(yùn)行呢?這應(yīng)該由洗刷線程來(lái)通知它已經(jīng)有工作可以做了,運(yùn)行drainningBoard的notify()調(diào)用可以做到這一點(diǎn):drainingBoard.addItem(plate);drainingBoard.n
28、otify();此時(shí),drainingBoard的等待隊(duì)列中第一個(gè)阻塞線程由隊(duì)列中釋放出來(lái),并可重新參加運(yùn)行的競(jìng)爭(zhēng)。解決方法如果等待隊(duì)列中沒(méi)有阻塞線程時(shí)調(diào)用了方法notify(),那么這個(gè)調(diào)用不做任何工作。notify()調(diào)用不會(huì)被保存到以后再發(fā)生效用。方法notify()最多只能釋放等待隊(duì)列中的第一個(gè)線程,如果有多個(gè)線程在等待,那么其他的線程將繼續(xù)留在隊(duì)列中。方法notifyAll()能夠在程序設(shè)計(jì)需要時(shí)釋放所有等待線程。解決方法Java中的實(shí)現(xiàn)并不像這里所假設(shè)的這樣簡(jiǎn)單。特別是,等待隊(duì)列本身構(gòu)成了一個(gè)特殊的數(shù)據(jù)結(jié)構(gòu),需要使用同步機(jī)制加以保護(hù)。在調(diào)用一個(gè)對(duì)象的wait(),notify()或
29、notifyAll()時(shí),必須首先持有該對(duì)象的鎖定標(biāo)志,因此這些方法必須在同步程序塊中調(diào)用。解決方法將代碼改變?nèi)缦拢簊ynchronized(drainingBoard)if (drainingBoard.isEmpty()drainingBoard.wait();解決方法同樣有:synchronized(drainingBoard)drainingBoard.addItem(plate);drainingBoard.notify();解決方法另外一個(gè)有趣的問(wèn)題:就是線程執(zhí)行被同步的語(yǔ)句時(shí)需要擁有對(duì)象的鎖定標(biāo)志,實(shí)際的實(shí)現(xiàn)過(guò)程中是不會(huì)出現(xiàn)這種情況的。Java將首先把鎖定標(biāo)志返回給對(duì)象,因此即使
30、一個(gè)線程由于執(zhí)行wait()調(diào)用而被阻塞,它也不會(huì)影響其他等待鎖定標(biāo)志的線程的運(yùn)行。解決方法當(dāng)一個(gè)線程被notify()后,它并不立即變?yōu)榭蓤?zhí)行狀態(tài),而僅僅是從等待隊(duì)列中移入鎖定標(biāo)志隊(duì)列中。這樣,在重新獲得鎖定標(biāo)志之前,它仍舊不能繼續(xù)運(yùn)行。另一方面,在實(shí)際實(shí)現(xiàn)中,方法wait()既可以被notify()終止,也可以通過(guò)調(diào)用線程的interrupt()方法來(lái)終止。后一種情況下,wait()會(huì)拋出一個(gè)InterruptedException異常,所以需要把它放在try/catch結(jié)構(gòu)中。解決方法線程狀態(tài)及狀態(tài)轉(zhuǎn)換示意圖:BlockedDeadNewbornRunnableRunningstop()
31、suspend()sleep()wait()start()stop()yield()stop()stop()resume()notify()綜合應(yīng)用實(shí)例現(xiàn)在來(lái)建立一個(gè)經(jīng)典的生產(chǎn)者/消費(fèi)者問(wèn)題的實(shí)際例子。提供以下兩個(gè)接口:public void push(char c);public char pop();綜合應(yīng)用實(shí)例首先來(lái)看生產(chǎn)者。生產(chǎn)者將隨機(jī)產(chǎn)生20個(gè)大寫(xiě)字母并將它們推入棧中,每次推入動(dòng)作之間有一個(gè)隨機(jī)的延時(shí),延時(shí)的范圍為0100ms。每個(gè)推入的字母將在屏幕上顯示。生產(chǎn)者線程public void run()char c;for (int i = 0; i 20; i+)c = (char)
32、(Math.random()*26+A);theStack.push(c);System.out.println(Produced: +c);tryThread.sleep(int)(Math.random()*100);catch (InterruptedException e) 消費(fèi)者線程消費(fèi)者從棧中取出20個(gè)字母,每次取出動(dòng)作之間有延時(shí),這里的延時(shí)為02s。這意味著棧的清空比填入要慢,因此棧能夠很快被完全填滿。消費(fèi)者線程public void run()char c;for (int i = 0; i 20; i+)c = theStack.pop();System.out.printl
33、n(Consuned: +c);try Thread.sleep(int)(Math.random()*1000);catch (InterruptedException e) 說(shuō)明棧需要一個(gè)索引值和一個(gè)緩沖區(qū)數(shù)組,因?yàn)楸纠且菔揪彌_區(qū)滿時(shí)正確的操作和同步方法,所以緩沖區(qū)僅設(shè)為能容納6個(gè)字母。一個(gè)新構(gòu)造的SyncStack應(yīng)該為空。構(gòu)造類(lèi)class SyncStackprivate int index = 0;private char buffer = new char6;public synchronized char pop() public synchronized void push
34、(char c) 推入和彈出方法public synchronized void push(char c)while(index = buffer.length)trythis.wait();catch(InterruptedException e) this.notify();buffer index = c;index+;public synchronized char pop()while(index = 0)trythis.wait();catch(InterruptedException e) this.notify();index-;return bufferindex;程序13-
35、17/最終的程序代碼: SyncTest.javapackage modl3;public class SyncTestpublic static void main(String args)SyncStack stack = new SyncStack();Runnable source = new Producer(stack);Runnable sink= new Consumer(stack);Thread t1 = new Thread(source);Thread t2 = new Thread(sink);t1.start();t2.start();/ Producer.java
36、package modl3;public class Producer implements RunnableSyncStack theStack;public Producer(SyncStack s)theStack = s;public void run()char c;for (int i = 0; i 20; i+)c = (char)(Math.random()*26+ A);theStack.push(c);System.out.println(Produced: +c);tryThread.sleep(int)(Math.random()*100);catch (Interru
37、ptedException e) / Consumer.javapackage modl3;public class Consumer implements RunnableSyncStack theStack;public Consumer(SyncStack s)theStack = s;public void run()char c;for (int i = 0; i 20; i+)c = theStack.pop();System.out.println(Consuned: +c);try Thread.sleep(int)(Math.random()*1000);catch (Int
38、erruptedException e) / SyncStack.javapackage modl3;public class SyncStackprivate int index = 0;private char buffer = new char6;public synchronized void push(char c)while(index = buffer.length)trythis.wait();catch(InterruptedException e) this.notify();bufferindex = c;index+;public synchronized char p
39、op()while(index = 0)trythis.wait();catch(InterruptedException e) this.notify();index-;return buffer index;G8JbMeQhTlWoZr%u(x+B2E6H9KcOfRiUmXp!s&v)z0C3F7IaLdPgSkVnYq$t*w-A1D5G8JbNeQhTlWo#r%u(y+B2E6H9LcOfRjUmXp!s&w)z0C4F7IaMdPhSkVnZq$t*x-A2D5G8KbNeQiTlXo#r%v(y+B3E6H9LcOgRjUmYp!s&w)z1C4F7JaMdPhSkWnZq$u
40、*x-A2D5H8KbNfQiTlXo#s%v(y0B3E6I9LdOgRjVmYp!t&w-z1C4G7JaMePhSkWnZr$u*x+A2D5H8KcNfQiUlXo#s%v)y0B3F6I9LdOgSjVmYq!t&w-z1D4G7JbMePhTkWoZr$u(x+A2E5H9KcNfRiUlXp#s%v)y0C3F6IaLdOgSjVnYq!t*w-z1D4G8JbMeQhTkWoZr%u(x+B2E5H9KcOfRiUmXp#s&v)z0C3F7IaLdPgSkVnYq$t*w-A1D5G8JbNeQhTlWoZr%u(y+B2E6H9KcOfRjUmXp!s&v)z0C4F7Ia
41、MdPgSkVnZq$t*x-A1D5G8KbNeQiTlWo#r%v(y+B3E6H9LcOgRjUmYp!s&w)z0C4F7JaMdPhSkVnZq$u*x-A2D5G8KbNfQiTlXo#r%v(y0B3E6I9LcOgRjVmYp!t&w)z1C4G7JaMePhSkWnZr$u*x+A2D5H8KbNfQiUlXo#s%v(y0B3F6I9LdOgRjVmYq!t&w-z1C4G7JbMePhTkWnZr$u(x+A2E5H8KcNfRiUlXp#s%v)y0C3F6IaLdOgSjVnYq!t*w-z1D4G7JbMeQhTkWoZr$u(x+B2E5H9KcNfRiUmXp#
42、s&v)y0C3F7IaLdPgSjVnYq$t*w-A1D4G8JbNeQhTlWoZr%u(y+B2E6H9KcOfRiUmXp!s&v)z0C3F7IaMdPgSkVnYq$t*x-A1D5G8JbNeQiTlWo#r%u(y+B3E6H9LcOfRjUmYp!s&w)z0C4F7JaMdPhSkVnZq$u*x-A2D5G8KbNeQiTlXo#r%v(y+B3E6I9LcOgRjUmYp!t&w)z1C4F7JaMePhSkWnZq$u*x+A2D5H8KbNfQiUlXo#s%v(y0B3F6I9LdOgRjVmYp!t&w-z1C4G7JaMePhTkWnZr$u*x+A2E5H
43、8KcNfQiUlXp#s%v)y0B3F6IaLdOgSjVmYq!t*w-z1D4G7JbMeQhTkWoZr$u(x+A2E5H9KcNfRiUlXp#s&v)y0C3F6IaLdPgSjVnYq!t*w-A1D4G8JbMeQhTlWoZr%u(x+B2E6H9KcOfRiUmXp!s&v)z0C3F7IaMdPgSkVnYq$t*w-A1D5G8JbNeQhTlWo#r%u(y+B2E6H9LcOfRjUmXp!s&w)z0C4F7IaMdPhSkVnZq$t*x-A2D5G8KbNeQiTlXo#r%v(y+B3E6H9LcOgRjUmYp!s&w)z1C4F7JaMdPhSkWn
44、Zq$u*x-A2D5H8KbNfQiTlXo#s%v(y0BIaMdPhSkVnZq$t*x-A2D5G8KbNeQiTlWo#r%v(y+B3E6H9LcOgRjUmYp!s&w)z1C4F7JaMdPhSkWnZq$u*x-A2D5H8KbNfQiTlXo#s%v(y0B3E6I9LdOgRjVmYp!t&w)z1C4G7JaMePhSkWnZr$u*x+A2D5H8KcNfQiUlXo#s%v)y0B3F6I9LdOgSjVmYq!t&w-z1D4G7JbMePhTkWoZr$u(x+A2E5H8KcNfRiUlXp#s%v)y0C3F6IaLdOgSjVnYq!t*w-z1D4G8J
45、bMeQhTkWoZr%u(x+B2E5H9KcOfRiUmXp#s&v)z0C3F7IaLdPgSkVnYq$t*w-A1D4G8JbNeQhTlWoZr%u(y+B2E6H9KcOfRjUmXp!s&v)z0C4F7IaMdPgSkVnZq$t*x-A1D5G8KbNeQiTlWo#r%v(y+B3E6H9LcOfRnYq$t*w-A1D4G8JbNeQhTlWoZr%u(y+B2E6H9KcOfRjUmXp!s&v)z0C4F7IaMdPgSkVnZq$t*x-A1D5G8KbNeQiTlWo#r%u(y+B3E6H9LcOfRjUmYp!s&w)z0C4F7JaMdPhSkVnZq$u
46、*x-A2D5G8KbNfQiTlXo#r%v(y0B3E6I9LcOgRjVmYp!t&w)z1C4F7JaMePhSkWnZq$u*x+A2D5H8KbNfQiUlXo#s%v(y0B3F6I9LdOgRjVmYq!t&w-z1C4G7JbMePhTkWnZr$u(x+A2E5H8KcNfQiUlXp#s%v)y0B3F6IaLdOgSjVmYq!t*w-z1D4G7JbMeQhTkWoZr$u(x+B2E5H9KcNfRiUmXp#s&v)y0C3F7IaLdPgSjVnYq$t*w-A1D4G8JbMeQhTlWoZr%u(x+B2E6H9KcOfRiUmXp!s&v)z0C3F7Ia
47、MdPgSkVnYq$t*x-A1D5G8JbNeQiTlWo#r%u(y+B3E6H9LcOfRjUmXp!s&w)z0C4F7IaMdPhSkVnZq$t*x-A2D5G8KbNeQiTlXo#r%v(y+B3E6I9LcOgRjUmYp!t&w)z1C4F7JaMePhSkWnZq$u*x+A2D5H8KbNfQiTlXo#s%v(y0B3E6I9LdOgRjVmYp!t&w-z1C4G7JaMePhTkWnZr$u*x+A2E5H8KcNfQiUlXp#s%v)y0B3F6IaLdOgSjVmYq!t&w-z1D4G7JbMePhTkWoZr$u(x+A2E5H9KcNfRiUlXp#
48、s&v)y0C3F6IaLdPgSjVnYq!t*w-A1D4G8JbMeQhTlWoZr%u(x+B2E5H9KcOfRiUmXp#s&v)z0C3F7IaLdPgSkVnYq$t*w-A1D5G8JbNeQhTlWo#r%u(y+B2E6H9LcOfRjUmXp!s&w)z0C4F7IaMdPhSZr%u(x+B2E5H9KcOfRiUmXp#s&v)z0C3F7IaLdPgSkVnYq$t*w-A1D5G8JbNeQhTlWo#r%u(y+B2E6H9LcOfRjUmXp!s&v)z0C4F7IaMdPgSkVnZq$t*x-A1D5G8KbNeQiTlWo#r%v(y+B3E6H9Lc
49、OgRjUmYp!s&w)z1C4F7JaMdPhSkWnZq$u*x-A2D5H8KbNfQiTlXo#r%v(y0B3E6I9LcOgRjVmYp!t&w)z1C4G7JaMePhSkWnZr$u*x+A2D5H8KcNfQiUlXo#s%v)y0B3F6I9LdOgSjVmYq!t&w-z1C4G7JbMePhTkWnZr$u(x+A2E5H8KcNfRiUlXp#s%v)y0C3F6IaLdOgSjVnYq!t*w-z1D4G8JbMeQhTkWoZr%u(x+B2E5H9KcNfRiUmXp#s&v)y0C3F7IaLdPgSjVnYq$t*w-A1D4G8JbNeQhTlWoZr%u(y+B2E6H9KcOfRjUmXp!s&v)z0C4F7IaMdPgSkVnZq$t*x-A1D5G8JbNeQiTlWo#r%u(y+B3E6H9LcOfRjUmYp!s&w)z0C4F7JaMdPhSkVnZq$u*x-A2D5G8KbNfQiTlXo#r%v(y0B3E6I9LcOgRjUmYp!t
溫馨提示
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 現(xiàn)代產(chǎn)品設(shè)計(jì)中的民族圖案與色彩研究
- 現(xiàn)代紋樣設(shè)計(jì)在商業(yè)品牌推廣中的應(yīng)用實(shí)踐
- 現(xiàn)代辦公環(huán)境下的AI餐廳服務(wù)應(yīng)用研究
- 現(xiàn)代物流行業(yè)的服務(wù)創(chuàng)新與升級(jí)
- 現(xiàn)代辦公環(huán)境下的報(bào)告制作技巧
- 2024年五年級(jí)語(yǔ)文上冊(cè) 第六單元 口語(yǔ)交際:父母之愛(ài)說(shuō)課稿 新人教版
- Module7 Unit2 This little girl can't walk(Period 1) (說(shuō)課稿) -2024-2025學(xué)年外研版(三起)英語(yǔ)五年級(jí)上冊(cè)
- 7《什么比獵豹的速度更快》說(shuō)課稿-2024-2025學(xué)年五年級(jí)上冊(cè)語(yǔ)文統(tǒng)編版001
- 13美麗的冬天 說(shuō)課稿-2024-2025學(xué)年道德與法治一年級(jí)上冊(cè)統(tǒng)編版
- 2024-2025學(xué)年高中化學(xué) 第1章 第4節(jié) 第2課時(shí) 有機(jī)物分子式與分子結(jié)構(gòu)的確定說(shuō)課稿 新人教版選修5
- 金屬非金屬礦山重大生產(chǎn)安全事故隱患判定標(biāo)準(zhǔn)課件
- 四年級(jí)上冊(cè)數(shù)學(xué)課件-一般應(yīng)用題 全國(guó)通用(共26張PPT)
- 肝臟炎性假瘤的影像學(xué)表現(xiàn)培訓(xùn)課件
- 國(guó)家行政機(jī)關(guān)公文格式課件
- 業(yè)務(wù)員回款考核辦法
- 急性心梗的護(hù)理業(yè)務(wù)學(xué)習(xí)課件
- 2021年投標(biāo)部工作計(jì)劃
- 導(dǎo)向標(biāo)識(shí)系統(tǒng)設(shè)計(jì)(二)課件
- 好書(shū)推薦《西游記》共33張幻燈片
- 聚焦:如何推進(jìn)教育治理體系和治理能力現(xiàn)代化
- 化工儀表自動(dòng)化【第四章】自動(dòng)控制儀表
評(píng)論
0/150
提交評(píng)論