Java多線(xiàn)程(一)線(xiàn)程的5種狀態(tài)及轉(zhuǎn)換

線(xiàn)程和進(jìn)程

線(xiàn)程和進(jìn)程定義:

一、進(jìn)程是具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合上的一次運(yùn)行活動(dòng),是系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位。

二、線(xiàn)程是進(jìn)程的一個(gè)實(shí)體,是CPU調(diào)度和分派的基本單位,他是比進(jìn)程更小的能獨(dú)立運(yùn)行的基本單位,線(xiàn)程自己基本上不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源(如程序計(jì)數(shù)器,一組寄存器和棧),一個(gè)線(xiàn)程可以創(chuàng)建和撤銷(xiāo)另一個(gè)線(xiàn)程;

進(jìn)程和線(xiàn)程的關(guān)系:

(1)一個(gè)線(xiàn)程只能屬于一個(gè)進(jìn)程,而一個(gè)進(jìn)程可以有多個(gè)線(xiàn)程,但至少有一個(gè)線(xiàn)程。

(2)資源分配給進(jìn)程,同一進(jìn)程的所有線(xiàn)程共享該進(jìn)程的所有資源。

(3)線(xiàn)程在執(zhí)行過(guò)程中,需要協(xié)作同步。不同進(jìn)程的線(xiàn)程間要利用消息通信的辦法實(shí)現(xiàn)同步。

(4)處理機(jī)分給線(xiàn)程,即真正在處理機(jī)上運(yùn)行的是線(xiàn)程。

(5)線(xiàn)程是指進(jìn)程內(nèi)的一個(gè)執(zhí)行單元,也是進(jìn)程內(nèi)的可調(diào)度實(shí)體。

線(xiàn)程與進(jìn)程的區(qū)別:

(1)調(diào)度:線(xiàn)程作為調(diào)度和分配的基本單位,進(jìn)程作為擁有資源的基本單位。

(2)并發(fā)性:不僅進(jìn)程之間可以并發(fā)執(zhí)行,同一個(gè)進(jìn)程的多個(gè)線(xiàn)程之間也可以并發(fā)執(zhí)行。

(3)擁有資源:進(jìn)程是擁有資源的一個(gè)獨(dú)立單位,線(xiàn)程不擁有系統(tǒng)資源,但可以訪(fǎng)問(wèn)隸屬于進(jìn)程的資源。

(4)系統(tǒng)開(kāi)銷(xiāo):在創(chuàng)建或撤銷(xiāo)進(jìn)程的時(shí)候,由于系統(tǒng)都要為之分配和回收資源,導(dǎo)致系統(tǒng)的明顯大于創(chuàng)建或撤銷(xiāo)線(xiàn)程時(shí)的開(kāi)銷(xiāo)。但進(jìn)程有獨(dú)立的地址空間,進(jìn)程崩潰后,在保護(hù)模式下不會(huì)對(duì)其他的進(jìn)程產(chǎn)生影響,而線(xiàn)程只是一個(gè)進(jìn)程中的不同的執(zhí)行路徑。線(xiàn)程有自己的堆棧和局部變量,但線(xiàn)程之間沒(méi)有單獨(dú)的地址空間,一個(gè)線(xiàn)程死掉就等于整個(gè)進(jìn)程死掉,所以多進(jìn)程的程序要比多線(xiàn)程的程序健壯,但是在進(jìn)程切換時(shí),耗費(fèi)的資源較大,效率要差些。

線(xiàn)程的劃分尺度小于進(jìn)程,使得多線(xiàn)程程序的并發(fā)性高。

另外,進(jìn)程在執(zhí)行過(guò)程中擁有獨(dú)立的內(nèi)存單元,而多個(gè)線(xiàn)程共享內(nèi)存,從而極大的提高了程序運(yùn)行效率。

線(xiàn)程在執(zhí)行過(guò)程中,每個(gè)獨(dú)立的線(xiàn)程有一個(gè)程序運(yùn)行的入口,順序執(zhí)行序列和程序的出口。但是線(xiàn)程不能夠獨(dú)立執(zhí)行,必須依存在應(yīng)用程序中,有應(yīng)用程序提供多個(gè)線(xiàn)程執(zhí)行控制。

從邏輯角度看,多線(xiàn)程的意義子啊與一個(gè)應(yīng)用程序中,有多個(gè)執(zhí)行部分可以同時(shí)執(zhí)行。但操作系統(tǒng)并沒(méi)有將多個(gè)線(xiàn)程看做多個(gè)獨(dú)立的應(yīng)用,來(lái)實(shí)現(xiàn)進(jìn)程的調(diào)度和管理以及資源分配。這就是進(jìn)程和線(xiàn)程的重要區(qū)別。

Java中的線(xiàn)程的生命周期大體可分為5種狀態(tài)。

1.新建(NEW):新創(chuàng)建了一個(gè)線(xiàn)程對(duì)象。

2.可運(yùn)行(RUNNABLE):線(xiàn)程對(duì)象創(chuàng)建后,其他線(xiàn)程(比如main線(xiàn)程)調(diào)用了該對(duì)象的start()方法。該狀態(tài)的線(xiàn)程位于可運(yùn)行線(xiàn)程池中,等待被線(xiàn)程調(diào)度選中,獲取cpu 的使用權(quán) 。

3.運(yùn)行(RUNNING):可運(yùn)行狀態(tài)(runnable)的線(xiàn)程獲得了cpu 時(shí)間片(timeslice) ,執(zhí)行程序代碼。

4.阻塞(BLOCKED):阻塞狀態(tài)是指線(xiàn)程因?yàn)槟撤N原因放棄了cpu 使用權(quán),也即讓出了cpu timeslice,暫時(shí)停止運(yùn)行。直到線(xiàn)程進(jìn)入可運(yùn)行(runnable)狀態(tài),才有機(jī)會(huì)再次獲得cpu timeslice 轉(zhuǎn)到運(yùn)行(running)狀態(tài)。阻塞的情況分三種:

等待阻塞:運(yùn)行(running)的線(xiàn)程執(zhí)行o.wait()方法,JVM會(huì)把該線(xiàn)程放入等待隊(duì)列(waitting queue)中。

同步阻塞:運(yùn)行(running)的線(xiàn)程在獲取對(duì)象的同步鎖時(shí),若該同步鎖被別的線(xiàn)程占用,則JVM會(huì)把該線(xiàn)程放入鎖池(lock pool)中。

其他阻塞:運(yùn)行(running)的線(xiàn)程執(zhí)行Thread.sleep(long ms)或t.join()方法,或者發(fā)出了I/O請(qǐng)求時(shí),JVM會(huì)把該線(xiàn)程置為阻塞狀態(tài)。當(dāng)sleep()狀態(tài)超時(shí)、join()等待線(xiàn)程終止或者超時(shí)、或者I/O處理完畢時(shí),線(xiàn)程重新轉(zhuǎn)入可運(yùn)行(runnable)狀態(tài)。

5.死亡(DEAD):線(xiàn)程run()、main() 方法執(zhí)行結(jié)束,或者因異常退出了run()方法,則該線(xiàn)程結(jié)束生命周期。死亡的線(xiàn)程不可再次復(fù)生。



線(xiàn)程狀態(tài)圖


Note:

1. sleep() 是Thread的靜態(tài)方法,最好不要用Thread的實(shí)例對(duì)象調(diào)用它,因?yàn)樗叩氖冀K是當(dāng)前正在運(yùn)行的線(xiàn)程,而不是調(diào)用它的線(xiàn)程對(duì)象,它只對(duì)正在運(yùn)行狀態(tài)的線(xiàn)程對(duì)象有效。

2. Java線(xiàn)程調(diào)度是Java多線(xiàn)程的核心,只有良好的調(diào)度,才能充分發(fā)揮系統(tǒng)的性能,提高程序的執(zhí)行效率。但是不管程序員怎么編寫(xiě)調(diào)度,只能最大限度的影響線(xiàn)程執(zhí)行的次序,而不能做到精準(zhǔn)控制。使用sleep方法之后,線(xiàn)程是進(jìn)入阻塞狀態(tài)的,只有當(dāng)睡眠的時(shí)間結(jié)束,才會(huì)重新進(jìn)入到就緒狀態(tài),而就緒狀態(tài)進(jìn)入到運(yùn)行狀態(tài),是由系統(tǒng)控制的,我們不可能精準(zhǔn)的去干涉它,所以如果調(diào)用Thread.sleep(1000)使得線(xiàn)程睡眠1秒,可能結(jié)果會(huì)大于1秒。

3.?yield()方法

yield()方法和sleep()方法有點(diǎn)相似,也是Thread類(lèi)提供的一個(gè)靜態(tài)的方法,它也可以讓當(dāng)前正在執(zhí)行的線(xiàn)程暫停,讓出cpu資源給其他的線(xiàn)程。但是和sleep()方法不同的是,它不會(huì)進(jìn)入到阻塞狀態(tài),而是進(jìn)入到就緒狀態(tài)。

4. join()方法,線(xiàn)程合并

線(xiàn)程的合并的含義就是將幾個(gè)并行線(xiàn)程的線(xiàn)程合并為一個(gè)單線(xiàn)程執(zhí)行,應(yīng)用場(chǎng)景是當(dāng)一個(gè)線(xiàn)程必須等待另一個(gè)線(xiàn)程執(zhí)行完畢才能執(zhí)行時(shí),Thread類(lèi)提供了join方法來(lái)完成這個(gè)功能,注意,它不是靜態(tài)方法。從上面的方法的列表可以看到,它有3個(gè)重載的方法:

- void?join()

?當(dāng)前線(xiàn)程等待加入該線(xiàn)程后面,等待該線(xiàn)程終止。即,等待該線(xiàn)程執(zhí)行完畢后再執(zhí)行當(dāng)前線(xiàn)程。

- void?join(long?millis)

當(dāng)前線(xiàn)程等待該線(xiàn)程終止的時(shí)間最長(zhǎng)為 millis 毫秒。 如果在millis時(shí)間內(nèi),該線(xiàn)程沒(méi)有執(zhí)行完,那么當(dāng)前線(xiàn)程進(jìn)入就緒狀態(tài),重新等待cpu調(diào)度

- void?join(long?millis,int?nanos)

等待該線(xiàn)程終止的時(shí)間最長(zhǎng)為 millis 毫秒 + nanos 納秒。如果在millis時(shí)間內(nèi),該線(xiàn)程沒(méi)有執(zhí)行完,那么當(dāng)前線(xiàn)程進(jìn)入就緒狀態(tài),重新等待cpu調(diào)度


5.守護(hù)線(xiàn)程

守護(hù)線(xiàn)程與普通線(xiàn)程寫(xiě)法上基本么啥區(qū)別,調(diào)用線(xiàn)程對(duì)象的方法setDaemon(true),則可以將其設(shè)置為守護(hù)線(xiàn)程。

setDaemon方法的詳細(xì)說(shuō)明:

public final void setDaemon(boolean on)將該線(xiàn)程標(biāo)記為守護(hù)線(xiàn)程或用戶(hù)線(xiàn)程。當(dāng)正在運(yùn)行的線(xiàn)程都是守護(hù)線(xiàn)程時(shí),Java 虛擬機(jī)退出。該方法必須在啟動(dòng)線(xiàn)程前調(diào)用。

實(shí)際上:JRE判斷程序是否執(zhí)行結(jié)束的標(biāo)準(zhǔn)是所有的前臺(tái)執(zhí)線(xiàn)程行完畢了,而不管后臺(tái)線(xiàn)程的狀態(tài),因此,在使用后臺(tái)線(xiàn)程(守護(hù)線(xiàn)程)時(shí)候一定要注意這個(gè)問(wèn)題。

守護(hù)線(xiàn)的好處就是你不需要關(guān)心它的結(jié)束問(wèn)題。例如你在你的應(yīng)用程序運(yùn)行的時(shí)候希望播放背景音樂(lè),如果將這個(gè)播放背景音樂(lè)的線(xiàn)程設(shè)定為非守護(hù)線(xiàn)程,那么在用戶(hù)請(qǐng)求退出的時(shí)候,

不僅要退出主線(xiàn)程,還要通知播放背景音樂(lè)的線(xiàn)程退出;如果設(shè)定為守護(hù)線(xiàn)程則不需要了。


6.如何結(jié)束一個(gè)線(xiàn)程

Thread.stop()、Thread.suspend、Thread.resume、Runtime.runFinalizersOnExit這些終止線(xiàn)程運(yùn)行的方法已經(jīng)被廢棄了,使用它們是極端不安全的!

想要安全有效的結(jié)束一個(gè)線(xiàn)程,只要保證在一定的情況下,run方法能夠執(zhí)行完畢即可。而不是while(true)的無(wú)線(xiàn)循環(huán)。

有些時(shí)候線(xiàn)程的run()方法不能正常的執(zhí)行完畢(可能在運(yùn)行時(shí)轉(zhuǎn)成了阻塞),這種情況下可以借助Thread對(duì)象的interrupt()方法將中斷狀態(tài)設(shè)置為true來(lái)結(jié)束一個(gè)線(xiàn)程。

當(dāng)一個(gè)線(xiàn)程處于sleep、wait、join這三種狀態(tài)之一的時(shí)候,如果此時(shí)他的中斷狀態(tài)為true,那么它就會(huì)拋出一個(gè)InterruptedException的異常,并將中斷狀態(tài)重新設(shè)置為false。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容