多線(xiàn)程教學(xué)講解課件_第1頁(yè)
多線(xiàn)程教學(xué)講解課件_第2頁(yè)
多線(xiàn)程教學(xué)講解課件_第3頁(yè)
多線(xiàn)程教學(xué)講解課件_第4頁(yè)
多線(xiàn)程教學(xué)講解課件_第5頁(yè)
已閱讀5頁(yè),還剩63頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(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ì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論