Java語言程序設(shè)計(jì)-第九章-線程_第1頁(yè)
Java語言程序設(shè)計(jì)-第九章-線程_第2頁(yè)
Java語言程序設(shè)計(jì)-第九章-線程_第3頁(yè)
Java語言程序設(shè)計(jì)-第九章-線程_第4頁(yè)
Java語言程序設(shè)計(jì)-第九章-線程_第5頁(yè)
已閱讀5頁(yè),還剩45頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、Java語言程序設(shè)計(jì)第九章 線程第9講 多線程 多線程基本概念 創(chuàng)建線程的方式 線程的生命周期及控制 線程的優(yōu)先級(jí)及調(diào)度 多線程的互斥與同步 守護(hù)線程 (Daemon) 線程組 (ThreadGroup) 程序:是一段靜態(tài)的代碼,它是應(yīng)用軟件執(zhí)行的藍(lán)本。進(jìn)程:是程序的一次動(dòng)態(tài)執(zhí)行過程,它對(duì)應(yīng)了從代碼加載、執(zhí)行至執(zhí)行完畢的一個(gè)完整過程,這個(gè)過程也是進(jìn)程本身從產(chǎn)生、發(fā)展至消亡的過程。線程是比進(jìn)程更小的執(zhí)行單位。一個(gè)進(jìn)程在其執(zhí)行過程中,可以產(chǎn)生多個(gè)線程,形成多條執(zhí)行線索,每條線索,即每個(gè)線程也有它自身的產(chǎn)生、存在和消亡的過程,也是一個(gè)動(dòng)態(tài)的概念。1、多線程基本概念操作系統(tǒng)為每個(gè)進(jìn)程分配一段內(nèi)存空間,

2、 包括:代碼、數(shù)據(jù)以及堆棧等資源多任務(wù)的操作系統(tǒng)(OS)中,進(jìn)程切換對(duì) CPU資源消耗較大多線程是指一個(gè)進(jìn)程中同時(shí)運(yùn)行的多個(gè)完成不同子任務(wù)的線程。多線程不僅可以使一個(gè)程序同時(shí)完成多項(xiàng)任務(wù),而且為此消耗的系統(tǒng)資源也比進(jìn)程方法少許多1、多線程基本概念并發(fā)現(xiàn)象在現(xiàn)實(shí)生活中大量存在人體(消化、運(yùn)動(dòng))計(jì)算機(jī)(同時(shí)運(yùn)行多種程序)多線程在一個(gè)程序中實(shí)現(xiàn)并發(fā)編程語言一般提供了串行程序設(shè)計(jì)的方法計(jì)算機(jī)的并發(fā)能力由操作系統(tǒng)提供Java在語言級(jí)提供多線程并發(fā)的概念1、多線程基本概念1、多線程基本概念 以前所編寫的程序,每個(gè)程序都有一個(gè)入口、一個(gè)出口以及一個(gè)順序執(zhí)行的序列,在程序執(zhí)行過程中的任何指定時(shí)刻,都只有一個(gè)單

3、獨(dú)的執(zhí)行點(diǎn)。 事實(shí)上,在單個(gè)程序內(nèi)部是可以在同一時(shí)刻進(jìn)行多種運(yùn)算的,這就是所謂的多線程(這與多任務(wù)的概念有相似之處)。 一個(gè)單獨(dú)的線程和順序程序相似,也有一個(gè)入口、一個(gè)出口以及一個(gè)順序執(zhí)行的序列,從概念上說,一個(gè)線程是一個(gè)程序內(nèi)部的一個(gè)順序控制流。 線程并不是程序,它自己本身并不能運(yùn)行,必須在程序中運(yùn)行。在一個(gè)程序中可以實(shí)現(xiàn)多個(gè)線程,這些線程同時(shí)運(yùn)行,完成不同的功能。1、多線程基本概念 從邏輯的觀點(diǎn)來看,多線程意味著一個(gè)程序的多行語句同時(shí)執(zhí)行,但是多線程并不等于多次啟動(dòng)一個(gè)程序,操作系統(tǒng)也不會(huì)把每個(gè)線程當(dāng)作獨(dú)立的進(jìn)程來對(duì)待: 兩者的粒度不同,是兩個(gè)不同層次上的概念。進(jìn)程是由操作系統(tǒng)來管理的,而

4、線程則是在一個(gè)程序(進(jìn)程)內(nèi)。 不同進(jìn)程的代碼、內(nèi)部數(shù)據(jù)和狀態(tài)都是完全獨(dú)立的,而一個(gè)程序內(nèi)的多線程是共享同一塊內(nèi)存空間和同一組系統(tǒng)資源,有可能互相影響。 線程本身的數(shù)據(jù)通常只有寄存器數(shù)據(jù),以及一個(gè)程序執(zhí)行時(shí)使用的堆棧,所以線程的切換比進(jìn)程切換的負(fù)擔(dān)要小。1、多線程基本概念進(jìn)程:程序的一次執(zhí)行。程序代碼程序數(shù)據(jù)程序資源線程:進(jìn)程中程序代碼的一個(gè)執(zhí)行序列。程序調(diào)用堆棧線程局部變量可共享訪問進(jìn)程中的數(shù)據(jù)和資源操作系統(tǒng)按線程來調(diào)度程序的執(zhí)行1、多線程基本概念文件輸入輸出裝置各種系統(tǒng)資源數(shù)據(jù)區(qū)段程序區(qū)段只有一個(gè)地方在執(zhí)行文件輸入輸出裝置各種系統(tǒng)資源數(shù)據(jù)區(qū)段程序區(qū)段同時(shí)有數(shù)個(gè)地方在執(zhí)行傳統(tǒng)的進(jìn)程多線程的任

5、務(wù)1、多線程基本概念1、多線程基本概念多線程的優(yōu)勢(shì): 多線程編程簡(jiǎn)單,效率高(能直接共享數(shù)據(jù)和資源,多進(jìn)程不能) 適合于開發(fā)服務(wù)程序(如Web服務(wù),聊天服務(wù)等) 適合于開發(fā)有多種交互接口的程序(如聊天程序的客戶端,網(wǎng)絡(luò)下載工具) 適合于有人機(jī)交互又有計(jì)算量的程序(如字處理程序Word,Excel) 減輕編寫交互頻繁、涉及面多的程序的困難(如監(jiān)聽網(wǎng)絡(luò)端口) 程序的吞吐量會(huì)得到改善(同時(shí)監(jiān)聽多種設(shè)備,如網(wǎng)絡(luò)端口、串口、并口以及其他外設(shè)) 有多個(gè)處理器的系統(tǒng),可以并發(fā)運(yùn)行不同的線程(否則,任何時(shí)刻只有一個(gè)線程在運(yùn)行)1、多線程基本概念 雖然各種操作系統(tǒng)(Unix/Linux、Windows系列等)都

6、支持多線程,但若要用C、C+或其他語言編寫多線程程序是十分困難的,因?yàn)樗鼈儗?duì)數(shù)據(jù)同步的支持不充分。 對(duì)多線程的綜合支持是Java語言的一個(gè)重要特色,它提供了Thread類來實(shí)現(xiàn)多線程。在Java中,線程可以認(rèn)為是由三部分組成的: 虛擬CPU,封裝在java.lang.Thread類中,它控制著整個(gè)線程的運(yùn)行; 執(zhí)行的代碼,傳遞給Thread類,由Thread類控制順序執(zhí)行; 處理的數(shù)據(jù),傳遞給Thread類,是在代碼執(zhí)行過程中所要處理的數(shù)據(jù)。Java應(yīng)用程序總是從主類的main方法開始執(zhí)行。當(dāng)JVM加載代碼,發(fā)現(xiàn)main方法之后,就會(huì)啟動(dòng)一個(gè)線程,這個(gè)線程稱作“主線程”,該線程負(fù)責(zé)執(zhí)行main

7、方法。那么,在main方法中再創(chuàng)建的線程,就稱為主線程中的線程。如果main方法中沒有創(chuàng)建其他的線程,那么當(dāng)main方法執(zhí)行完最后一個(gè)語句,即main方法返回時(shí),JVM就會(huì)結(jié)束我們的Java應(yīng)用程序。如果main方法中又創(chuàng)建了其他線程,那么JVM就要在主線程和其他線程之間輪流切換,保證每個(gè)線程都有機(jī)會(huì)使用CPU資源,main方法即使執(zhí)行完最后的語句,JVM也不會(huì)結(jié)束我們的程序,JVM一直要等到主線程中的所有線程都結(jié)束之后,才結(jié)束我們的Java應(yīng)用程序。1、多線程基本概念 在Java語言中,用Thread類或子類創(chuàng)建線程對(duì)象。這一節(jié)講述怎樣用Thread子類創(chuàng)建對(duì)象。 用戶可以擴(kuò)展 Thread

8、類,但需要重寫父類的run方法,其目的是規(guī)定線程的具體操作,否則線程就什么也不做,因?yàn)楦割惖膔un方法中沒有任何操作語句。 下面例子中除主線程外還有兩個(gè)線程,這兩個(gè)線程分別在命令行窗口的左側(cè)和右側(cè)順序地一行一行地輸出字符串。主線程負(fù)責(zé)判斷輸出的行數(shù),當(dāng)其中任何一個(gè)線程輸出8行后,就結(jié)束進(jìn)程。本例題中用到了System類中的類方法:exit(int n),主線程使用該方法結(jié)束整個(gè)程序。 2、創(chuàng)建線程的方式 - Thread 的子類創(chuàng)建線程 使用Thread子類創(chuàng)建線程的優(yōu)點(diǎn)是:我們可以在子類中增加新的成員變量,使線程具有某種屬性,也可以在子類中新增加方法,使線程具有某種功能。但是,Java不支持

9、多繼承,Thread類的子類不能再擴(kuò)展其他的類。2、創(chuàng)建線程的方式 - Thread 的子類創(chuàng)建線程 1Runnable接口與目標(biāo)對(duì)象 創(chuàng)建線程的另一個(gè)途徑就是用Thread類直接創(chuàng)建線程對(duì)象。使用Thread創(chuàng)建線程對(duì)象時(shí),通常使用的構(gòu)造方法是: Thread(Runnable target), 該構(gòu)造方法中的參數(shù)是一個(gè)Runnable類型的接口,因此,在創(chuàng)建線程對(duì)象時(shí)必須向構(gòu)造方法的參數(shù)傳遞一個(gè)實(shí)現(xiàn)Runnable接口類的實(shí)例,該實(shí)例對(duì)象稱作所創(chuàng)線程的目標(biāo)對(duì)象,當(dāng)線程調(diào)用start方法后,一旦輪到它來享用CPU資源,目標(biāo)對(duì)象就會(huì)自動(dòng)調(diào)用接口中的run方法(接口回調(diào)),這一過程是自動(dòng)實(shí)現(xiàn)的,

10、用戶程序只需要讓線程調(diào)用start方法即可,也就是說,當(dāng)線程被調(diào)度并轉(zhuǎn)入運(yùn)行狀態(tài)時(shí),所執(zhí)行的就是run()方法中所規(guī)定的操作。例子:通過Runnable接口的方式創(chuàng)建線程 2、創(chuàng)建線程的方式 -使用Runable接口 我們知道線程間可以共享相同的內(nèi)存單元(包括代碼與數(shù)據(jù)),并利用這些共享單元來實(shí)現(xiàn)數(shù)據(jù)交換、實(shí)時(shí)通信與必要的同步操作。對(duì)于Thread(Runnable target)構(gòu)造方法創(chuàng)建的線程,輪到它來享用CPU資源時(shí),目標(biāo)對(duì)象就會(huì)自動(dòng)調(diào)用接口中的run方法,因此,對(duì)于使用同一目標(biāo)對(duì)象的線程,目標(biāo)對(duì)象的成員變量自然就是這些線程共享的數(shù)據(jù)單元。另外,創(chuàng)建目標(biāo)對(duì)象類在必要時(shí)還可以是某個(gè)特定類

11、的子類,因此,使用Runnable接口比使用Thread的子類更具有靈活性。 下面的例子中,兩個(gè)線程:zhang和cheng,使用同一目標(biāo)對(duì)象。兩個(gè)線程共享目標(biāo)對(duì)象的money。當(dāng)money的值小于100時(shí),線程zhang結(jié)束自己的run方法進(jìn)入死亡狀態(tài);當(dāng)money的值小于0時(shí),線程cheng結(jié)束自己的run方法進(jìn)入死亡狀態(tài)。2、創(chuàng)建線程的方式 -使用Runable接口 2關(guān)于run方法中的局部變量 對(duì)于具有相同目標(biāo)對(duì)象的線程,當(dāng)其中一個(gè)線程享用CPU資源時(shí),目標(biāo)對(duì)象自動(dòng)調(diào)用接口中的run方法,這時(shí),run方法中的局部變量被分配內(nèi)存空間,當(dāng)輪到另一個(gè)線程享用CPU資源時(shí),目標(biāo)對(duì)象會(huì)再次調(diào)用接

12、口中的run方法,那么,run方法中的局部變量會(huì)再次分配內(nèi)存空間。也就是說run方法已經(jīng)啟動(dòng)運(yùn)行了兩次,分別運(yùn)行在不同的線程中,即運(yùn)行在不同的時(shí)間片內(nèi)。不同線程的run方法中的局部變量互不干擾,一個(gè)線程改變了自己的run方法中局部變量的值不會(huì)影響其他線程的run方法中的局部變量??蠢?、創(chuàng)建線程的方式 -使用Runable接口例子:通過實(shí)例熟悉如何創(chuàng)建線程 1start() 線程調(diào)用該方法將啟動(dòng)線程,使之從新建狀態(tài)進(jìn)入就緒隊(duì)列排隊(duì),一旦輪到它來享用CPU資源時(shí),就可以脫離創(chuàng)建它的主線程獨(dú)立開始自己的生命周期了。 2run() Thread類的run()方法與Runnable接口中的run()

13、方法的功能和作用相同,都用來定義線程對(duì)象被調(diào)度之后所執(zhí)行的操作,都是系統(tǒng)自動(dòng)調(diào)用而用戶程序不得引用的方法。系統(tǒng)的Thread類中,run()方法沒有具體內(nèi)容,所以用戶程序需要?jiǎng)?chuàng)建自己的Thread類的子類,并重寫run()方法來覆蓋原來的run()方法。當(dāng)run方法執(zhí)行完畢,線程就變成死亡狀態(tài),所謂死亡狀態(tài)就是線程釋放了實(shí)體,即釋放分配給線程對(duì)象的內(nèi)存。在線程沒有結(jié)束run()方法之前,不贊成讓線程再調(diào)用start()方法,否則將發(fā)生ILLegalThreadStateException異常。 2、創(chuàng)建線程的方式 -線程的常用方法 3sleep(int millsecond) 線程的調(diào)度執(zhí)行是

14、按照其優(yōu)先級(jí)的高低順序進(jìn)行的,當(dāng)高級(jí)線程不完成,即未死亡時(shí),低級(jí)線程沒有機(jī)會(huì)獲得處理器。有時(shí),優(yōu)先級(jí)高的線程需要優(yōu)先級(jí)低的線程做一些工作來配合它,或者優(yōu)先級(jí)高的線程需要完成一些費(fèi)時(shí)的操作,此時(shí)優(yōu)先級(jí)高的線程應(yīng)該讓出處理器,使優(yōu)先級(jí)低的線程有機(jī)會(huì)執(zhí)行。為達(dá)到這個(gè)目的,優(yōu)先級(jí)高的線程可以在它的run()方法中調(diào)用sleep方法來使自己放棄處理器資源,休眠一段時(shí)間。休眠時(shí)間的長(zhǎng)短由sleep方法的參數(shù)決定,millsecond是毫秒為單位的休眠時(shí)間。如果線程在休眠時(shí)被打斷,JVM就拋出InterruptedException異常。因此,必須在trycatch語句塊中調(diào)用sleep方法。例子:線程的休

15、眠 2、創(chuàng)建線程的方式 -線程的常用方法 4isAlive() 檢查線程是否處于運(yùn)行狀態(tài)的方法,當(dāng)一個(gè)線程調(diào)用start()方法,并占有CUP資源后,該線程的run方法就開始運(yùn)行。在線程的run方法結(jié)束之前,即沒有進(jìn)入死亡狀態(tài)之前,線程調(diào)用isAlive()方法返回true,當(dāng)線程進(jìn)入死亡狀態(tài)后(實(shí)體內(nèi)存被釋放),線程仍可以調(diào)用方法isAlive(),這時(shí)返回的值是false。 需要注意的是,一個(gè)已經(jīng)運(yùn)行的線程在沒有進(jìn)入死亡狀態(tài)時(shí),不要再給線程分配實(shí)體,由于線程只能引用最后分配的實(shí)體,先前的實(shí)體就會(huì)成為“垃圾”,并且不會(huì)被垃圾收集機(jī)收集掉。 2、創(chuàng)建線程的方式 -線程的常用方法 現(xiàn)在讓我們看一

16、個(gè)例子,在下面的例子中一個(gè)線程每隔1秒鐘在命令行窗口輸出一句話:“你好!”,在輸出5句之后,該線程又被分配了實(shí)體,新實(shí)體又開始運(yùn)行。這時(shí),我們?cè)诿钚忻棵腌娔芸匆妰尚小澳愫谩?,因?yàn)槔鴮?shí)體仍然在工作。 2、創(chuàng)建線程的方式 -線程的常用方法 5currentThread() currentThread()方法是Thread類中的類方法,可以用類名調(diào)用,該方法返回當(dāng)前正在使用CPU資源的線程。 6interrupt() intertupt方法經(jīng)常用來“吵醒”休眠的線程。當(dāng)一些線程調(diào)用sleep方法處于休眠狀態(tài)時(shí),一個(gè)使用 CPU資源的其它線程在執(zhí)行過程中,可以讓休眠的線程分別調(diào)用interrupt

17、 方法“吵醒”自己,即導(dǎo)致休眠的線程發(fā)生InterruptedException異常,從而結(jié)束休眠,重新排隊(duì)等待CPU資源。 2、創(chuàng)建線程的方式 -線程的常用方法 在下面的例子中,有3個(gè)線程:zhangXiao、zhengMing和teacher,其中2個(gè)線程:zhangXiao和zhengMing準(zhǔn)備休眠10秒鐘后,再分別輸出“早上好!”和“good morning!”。teacher線程在輸出5句“上課”后,“吵醒”休眠的線程:zhangXiao和zhengMing。 2、創(chuàng)建線程的方式 -線程的常用方法3、 線程的生命周期及控制 線程是程序內(nèi)部的一個(gè)順序控制流,它具有一個(gè)特定的生命周期。

18、在一個(gè)線程的生命周期中,它總處于某一種狀態(tài)中。線程的狀態(tài)表示了線程正在進(jìn)行的活動(dòng)以及在這段時(shí)間內(nèi)線程能完成的任務(wù)。 1線程的4種狀態(tài) 在Java語言中,Thread類及其子類創(chuàng)建的對(duì)象稱作線程,新建的線程在它的一個(gè)完整的生命周期中通常要經(jīng)歷4種狀態(tài),(1)新建(new Thread) 當(dāng)創(chuàng)建了一個(gè)新的線程時(shí)( myThread thd = new myThread(); ),它就處于創(chuàng)建狀態(tài),此時(shí)它僅僅是一個(gè)空的線程對(duì)象,系統(tǒng)不為它分配資源。處于這種狀態(tài)時(shí)只能啟動(dòng)或終止該線程,調(diào)用除這兩種以外的其它線程狀態(tài)相關(guān)的方法都會(huì)失敗并且會(huì)引起非法狀態(tài)例外IllegalThreadStateExcept

19、ion(對(duì)于其它狀態(tài),若所調(diào)用的方法與狀態(tài)不符,都會(huì)引起非法狀態(tài)例外)。 3、線程的生命周期及控制(2)運(yùn)行 線程創(chuàng)建后僅僅是占有了內(nèi)存資源,在JVM管理的線程中還沒有這個(gè)線程,此線程必須調(diào)用start()方法(從父類繼承的方法)通知JVM,這樣JVM就會(huì)知道又有一個(gè)新一個(gè)線程排隊(duì)等候切換了。 當(dāng)JVM將CUP使用權(quán)切換給線程時(shí),如果線程是Thread的子類創(chuàng)建的,該類中的run方法就立刻執(zhí)行。所以我們必須在子類中重寫父類的run方法,Thread類中的run()方法沒有具體內(nèi)容,程序要在Thread類的子類中重寫run()方法來覆蓋父類的run()方法,run方法規(guī)定了該線程的具體使命。 在

20、線程沒有結(jié)束run方法之前,不要讓線程再調(diào)用start方法,否則將發(fā)生ILLegalThreadStateException異常。 3、線程的生命周期及控制(3)中斷 有4種原因的中斷:(a) JVM將CPU資源從當(dāng)前線程切換給其他線程,使本線程讓出CPU的使用權(quán)處于中斷狀態(tài)。(b)線程使用CPU資源期間,執(zhí)行了sleep(int millsecond)方法,使當(dāng)前線程進(jìn)入休眠狀態(tài)。sleep(int millsecond)方法是Thread類中的一個(gè)類方法,線程一旦執(zhí)行了sleep(int millsecond)方法,就立刻讓出CPU的使用權(quán),使當(dāng)前線程處于中斷狀態(tài)。經(jīng)過參數(shù)millseco

21、nd指定的豪秒數(shù)之后,該線程就重新進(jìn)到線程隊(duì)列中排隊(duì)等待CPU資源,以便從中斷處繼續(xù)運(yùn)行。 3、線程的生命周期及控制(c)線程使用CPU資源期間,執(zhí)行了wait()方法,使得當(dāng)前線程進(jìn)入等待狀態(tài)。等待狀態(tài)的線程不會(huì)主動(dòng)進(jìn)到線程隊(duì)列中排隊(duì)等待CPU資源,必須由其他線程調(diào)用notify()方法通知它,使得它重新進(jìn)到線程隊(duì)列中排隊(duì)等待CPU資源,以便從中斷處繼續(xù)運(yùn)行。有關(guān)wait、noftify和notifyAll方法將在后面詳細(xì)討論 (d) 線程使用CPU資源期間,執(zhí)行某個(gè)操作進(jìn)入阻塞狀態(tài),比如執(zhí)行讀/寫操作引起阻塞。進(jìn)入阻塞狀態(tài)時(shí)線程不能進(jìn)入排隊(duì)隊(duì)列,只有當(dāng)引起阻塞的原因消除時(shí),線程才重新進(jìn)到線

22、程隊(duì)列中排隊(duì)等待CPU資源,以便從原來中斷處開始繼續(xù)運(yùn)行。 3、線程的生命周期及控制 (4)死亡 處于死亡狀態(tài)的線程不具有繼續(xù)運(yùn)行的能力。線程死亡的原因有二,一個(gè)是正常運(yùn)行的線程完成了它的全部工作,即執(zhí)行完run方法中的全部語句,結(jié)束了run方法。另一個(gè)原因是線程被提前強(qiáng)制性地終止,即強(qiáng)制run方法結(jié)束。所謂死亡狀態(tài)就是線程釋放了實(shí)體,即釋放分配給線程對(duì)象的內(nèi)存。 現(xiàn)在,我們看一個(gè)完整的例子,通過分析運(yùn)行結(jié)果闡述線程的4種狀態(tài)。該例子中我們用Thread的子類:WriteWordThread創(chuàng)建了兩個(gè)線程。 3、線程的生命周期及控制 上述程序在不同的計(jì)算機(jī)運(yùn)行或在同一臺(tái)計(jì)算機(jī)反復(fù)運(yùn)行的結(jié)果不盡

23、相同,輸出結(jié)果依賴當(dāng)前CPU資源的使用情況。為了使結(jié)果盡量不依賴于當(dāng)前CPU資源的使用情況,我們應(yīng)當(dāng)讓線程主動(dòng)調(diào)用sleep方法讓出CPU的使用權(quán)進(jìn)入中斷狀態(tài),如下列代碼所示: 3、線程的生命周期及控制3、線程的生命周期及控制 isAlive()方法:可以用來判斷線程目前是否正在執(zhí)行中。如果線程已被啟動(dòng)并且未被終止,那么isAlive( )返回true,但該線程是可運(yùn)行或是不可運(yùn)行的,是不能作進(jìn)一步的分辨。如果返回false,則該線程是新創(chuàng)建或是已被終止的(同樣不能作進(jìn)一步的分辨)。 join()方法:等待線程執(zhí)行完畢。 yield()方法:將執(zhí)行的權(quán)力交給其它優(yōu)先級(jí)相同的線程,當(dāng)前執(zhí)行線程到

24、可運(yùn)行線程隊(duì)列(ready)的最后等待,若隊(duì)列空,該方法無效。myThread thd = new MyThread();thd.start();thd.join(); /等待線程thd執(zhí)行完后再繼續(xù)往下執(zhí)行join(int time):最多等待time所指定的時(shí)間。 sleep()方法可以暫停線程的執(zhí)行,讓其它線程得到機(jī)會(huì)。但sleep()要丟出例外InterruptedException ,必須抓住。try sleep(100)catch(InterruptedException e) /本例外可不作處理 suspend()方法和resume()可以用來暫停線程或恢復(fù)線程??梢杂删€程自身在

25、線程體中調(diào)用suspend()方法暫停自己,也可以在其他線程中通過線程實(shí)例調(diào)用suspend()方法暫停線程的執(zhí)行。但是要恢復(fù)由suspend()方法暫停的線程,只能在其他線程中通過線程實(shí)例調(diào)用resume()方法。3、線程的生命周期及控制 Java提供一個(gè)線程調(diào)度器來監(jiān)控程序中啟動(dòng)后進(jìn)入可運(yùn)行狀態(tài)的所有線程。線程調(diào)度器按照線程的優(yōu)先級(jí)決定調(diào)度哪些線程來執(zhí)行,具有高優(yōu)先級(jí)的線程會(huì)在較低優(yōu)先級(jí)的線程之前得到執(zhí)行。同時(shí)線程的調(diào)度是搶先式的,即如果當(dāng)前線程在執(zhí)行過程中,一個(gè)具有更高優(yōu)先級(jí)的線程進(jìn)入可執(zhí)行狀態(tài),則該高優(yōu)先級(jí)的線程會(huì)被立即調(diào)度執(zhí)行。 多個(gè)線程運(yùn)行時(shí),若線程的優(yōu)先級(jí)相同,由操作系統(tǒng)按時(shí)間片

26、輪轉(zhuǎn)方式或獨(dú)占方式來分配線程的執(zhí)行時(shí)間。 4、線程的優(yōu)先級(jí)及調(diào)度 在Java中線程的優(yōu)先級(jí)是用數(shù)字來表示的,分為三個(gè)級(jí)別: 低優(yōu)先級(jí):Thread.MIN_PRIORITY,數(shù)值為1 (24) 缺省優(yōu)先級(jí): Thread. NORM_PRIORITY,數(shù)值為5 高優(yōu)先級(jí):Thread.MAX_PRIORITY,數(shù)值為10 (69) 具有相同優(yōu)先級(jí)的多個(gè)線程,若它們都為高優(yōu)先級(jí)Thread.MAX_PRIORITY,則每個(gè)線程都是獨(dú)占式的,也就是說這些線程將被順序執(zhí)行;若該優(yōu)先級(jí)不為高優(yōu)先級(jí),則這些線程將同時(shí)執(zhí)行,也就是說這些線程的執(zhí)行是無序的。 線程被創(chuàng)建后,其缺省的優(yōu)先級(jí)是缺省優(yōu)先級(jí)Thre

27、ad. NORM_PRIORITY??梢杂梅椒?int getPriority()來獲得線程的優(yōu)先級(jí),同時(shí)也可以用方法 void setPriority( int p ) 在線程被創(chuàng)建后改變線程的優(yōu)先級(jí)。 4、線程的優(yōu)先級(jí)及調(diào)度在實(shí)際軟件系統(tǒng)中,許多線程之間有時(shí)會(huì)共享一些數(shù)據(jù),并且它們之間的狀態(tài)、行為是相互影響的。線程間共享的數(shù)據(jù)以及線程狀態(tài)、行為的相互影響有兩種:一種是線程間的互斥,一種是線程間的同步 5.1 共享資源問題5.2 互斥線程的設(shè)計(jì)方法5、多線程的互斥與同步 線程間的互斥5.1 共享資源問題共享資源是指在程序中并行運(yùn)行的若干個(gè)線程操作的數(shù)據(jù)資源相同在程序中,并行運(yùn)行的若干個(gè)線程操

28、作共享資源時(shí)可能出錯(cuò)。例如,在一個(gè)民航的售票系統(tǒng)中,一個(gè)售票處工作人員(甲)欲給一個(gè)客戶分配一個(gè)座位,于是調(diào)出飛機(jī)的座位分配圖,但當(dāng)甲察看座位分配圖時(shí),另外一個(gè)售票處的工作人員(乙)也在為其他客戶分配座位,乙也調(diào)出了這張飛機(jī)座位分配圖。乙為客戶分配了座位6A,同時(shí)在圖中標(biāo)記此座位(6A)已被分配。此時(shí),甲還在察看那張未被更新的座位分配圖,甲并不知道座位分配圖已經(jīng)發(fā)生了變化(座位6A已被分配),甲也為客戶分配了座位6A。這時(shí)問題就出現(xiàn)了,一個(gè)座位被兩個(gè)人同時(shí)擁有那么,問題出在哪里呢?顯然是飛機(jī)的座位分配圖,這是一個(gè)共享的數(shù)據(jù)。在一個(gè)工作人員使用它時(shí),應(yīng)該禁止其他工作人員使用它這類問題實(shí)際是一種生

29、產(chǎn)者-消費(fèi)者問題。生產(chǎn)者一次或多次提供貨物,若干個(gè)消費(fèi)者同時(shí)消費(fèi)。我們定義這種生產(chǎn)者-消費(fèi)者問題是生產(chǎn)者-消費(fèi)者模式 共享資源的互斥基于上述分析,應(yīng)當(dāng)認(rèn)識(shí)到,當(dāng)并行運(yùn)行的幾個(gè)線程操作共享資源,且問題的模型屬于生產(chǎn)者-消費(fèi)者模式時(shí),一定要保證操作的互斥,即一個(gè)共享資源每次只能由一個(gè)線程操作,當(dāng)這個(gè)線程還沒有操作完時(shí),不允許其他線程操作共享資源。只有這樣才能保證并行運(yùn)行的多個(gè)線程對(duì)共享資源操作的正確性5.2 互斥線程的設(shè)計(jì)方法互斥鎖是基于共享資源的互斥性設(shè)計(jì)的,用來標(biāo)記那些多個(gè)并行運(yùn)行的線程共享的資源。被用互斥鎖標(biāo)記的共享資源,在一個(gè)時(shí)間段內(nèi),只能有一個(gè)線程使用;只有當(dāng)加互斥鎖的線程使用完了該共享

30、資源,另一個(gè)線程才可以使用。這樣就可以保證線程對(duì)共享資源操作的正確性在Java語言中,引入了“對(duì)象互斥鎖”的概念(又稱為監(jiān)視器、管程)來實(shí)現(xiàn)不同線程對(duì)共享數(shù)據(jù)操作的同步。 “對(duì)象互斥鎖”阻止多個(gè)線程同時(shí)訪問同一個(gè)條件變量。 在Java語言中,有兩種方法可以實(shí)現(xiàn)“對(duì)象互斥鎖”: 用關(guān)鍵字volatile來聲明一個(gè)共享數(shù)據(jù)(變量); 用關(guān)鍵字synchronized來聲明一個(gè)操作共享數(shù)據(jù)的方法或一段代碼。為共享資源加互斥鎖的兩種方法:(1)鎖定一個(gè)對(duì)象和一段代碼聲明格式為: synchronized (對(duì)象名) 對(duì)象表示要鎖定的共享資源,一對(duì)花括號(hào)內(nèi)的語句組表示鎖定對(duì)象期間執(zhí)行的語句。此格式可以用

31、來在一個(gè)線程的一部分代碼上加互斥鎖當(dāng)一個(gè)線程執(zhí)行這段代碼時(shí),就鎖定了指定的對(duì)象這就形成了多個(gè)線程對(duì)同一個(gè)對(duì)象的“互斥”使用方式,因此該對(duì)象也稱為互斥對(duì)象(2)鎖定一個(gè)方法聲明格式為: synchronized 方法聲明 方法體 這里雖然沒有指出鎖定的對(duì)象,但是一個(gè)方法必然屬于一個(gè)類,因此,此格式鎖定的是該方法所屬類的對(duì)象,鎖定的范圍是整個(gè)方法 在下面的例子中有兩個(gè)線程:accountant和cashier,他倆共同擁有一個(gè)帳本。他倆都可以使用saveOrTake(int number)對(duì)帳本進(jìn)行訪問,會(huì)計(jì)使用saveOrTake方法時(shí),向帳本上寫入存錢記錄;出納使用saveOrTake方法時(shí),

32、向帳本寫入取錢記錄。因此,當(dāng)會(huì)計(jì)正在使用saveOrTake方法時(shí),出納被禁止使用,反之也是這樣。 為共享資源加互斥鎖的兩種方法:還有一種線程間對(duì)共享資源的相互影響,是一個(gè)線程的運(yùn)行要依賴于另一個(gè)線程對(duì)共享資源的處理結(jié)果,這稱為線程間的同步 5.3 資源同步問題5.4 同步線程的設(shè)計(jì)方法5、多線程的互斥與同步 線程間的同步5.3 資源同步問題一個(gè)計(jì)算機(jī)模擬生產(chǎn)-銷售問題。規(guī)定:(1)由于倉(cāng)庫(kù)有限,必須把倉(cāng)庫(kù)中的商品銷售完后才能再生產(chǎn);(2)由于擔(dān)心不能及時(shí)供貨被罰款,只有當(dāng)倉(cāng)庫(kù)中有貨時(shí)才能銷售。在這類問題中,兩個(gè)操作(生產(chǎn)和銷售)中的任何一個(gè)操作執(zhí)行的前提,是另一個(gè)操作已經(jīng)完成。另一個(gè)操作已經(jīng)

33、完成的標(biāo)志是共享資源(倉(cāng)庫(kù))滿足本操作的執(zhí)行條件。這樣一類問題也稱作生產(chǎn)者-消費(fèi)者問題。我們定義這種生產(chǎn)者-消費(fèi)者問題是生產(chǎn)者-消費(fèi)者模式。消費(fèi)者操作執(zhí)行的前提條件是生產(chǎn)者操作已經(jīng)生產(chǎn)了;生產(chǎn)者操作執(zhí)行的前提條件是消費(fèi)者已經(jīng)消費(fèi)了。在存在共享資源同步問題的程序設(shè)計(jì)中如果不考慮共享資源的同步問題,必然引起錯(cuò)誤 5.4 線程同步的設(shè)計(jì)方法線程同步的設(shè)計(jì)方法,是除了加互斥鎖外,還要在并行運(yùn)行的線程上加信號(hào)量信號(hào)量是一個(gè)標(biāo)志,表示一種操作(如生產(chǎn)或銷售)是否已執(zhí)行完,另一種操作(如銷售或生產(chǎn))是否可以執(zhí)行了。Object類提供了一組關(guān)于線程同步的方法:l void wait() 引起當(dāng)前線程等待l void notify()喚醒一個(gè)正在等待這個(gè)對(duì)象的線程l void notifyAll()喚醒所有正在等待這個(gè)對(duì)象的線程wait()方法的所謂等待,是把當(dāng)前線程從運(yùn)行狀態(tài)轉(zhuǎn)為阻塞狀態(tài)notify()方法的所謂喚醒,是把等待線程從阻塞狀態(tài)轉(zhuǎn)為可運(yùn)行狀態(tài),從而有機(jī)會(huì)讓線程調(diào)度程序調(diào)度進(jìn)入運(yùn)行狀態(tài)還有一點(diǎn)要說明的是:wait()方法所在的代碼段一定要加互斥鎖synchronized。

溫馨提示

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

最新文檔

評(píng)論

0/150

提交評(píng)論