Java中的線程的生命周期大體可分為5種狀態(tài)。
新建(NEW):新創(chuàng)建了一個(gè)線程對(duì)象。
可運(yùn)行(RUNNABLE):線程對(duì)象創(chuàng)建后,其他線程(比如main線程)調(diào)用了該對(duì)象的start()方法。該狀態(tài)的線程位于可運(yùn)行線程池中,等待被線程調(diào)度選中,獲取cpu 的使用權(quán) 。
運(yùn)行(RUNNING):可運(yùn)行狀態(tài)(runnable)的線程獲得了cpu 時(shí)間片(timeslice) ,執(zhí)行程序代碼。
阻塞(BLOCKED):阻塞狀態(tài)是指線程因?yàn)槟撤N原因放棄了cpu 使用權(quán),也即讓出了cpu timeslice,暫時(shí)停止運(yùn)行。直到線程進(jìn)入可運(yùn)行(runnable)狀態(tài),才有機(jī)會(huì)再次獲得cpu timeslice 轉(zhuǎn)到運(yùn)行(running)狀態(tài)。阻塞的情況分三種:
(一). 等待阻塞:運(yùn)行(running)的線程執(zhí)行o.wait()方法,JVM會(huì)把該線程放入等待隊(duì)列(waitting queue)中。
(二). 同步阻塞:運(yùn)行(running)的線程在獲取對(duì)象的同步鎖時(shí),若該同步鎖被別的線程占用,則JVM會(huì)把該線程放入鎖池(lock pool)中。
(三). 其他阻塞:運(yùn)行(running)的線程執(zhí)行Thread.sleep(long ms)或t.join()方法,或者發(fā)出了I/O請(qǐng)求時(shí),JVM會(huì)把該線程置為阻塞狀態(tài)。當(dāng)sleep()狀態(tài)超時(shí)、join()等待線程終止或者超時(shí)、或者I/O處理完畢時(shí),線程重新轉(zhuǎn)入可運(yùn)行(runnable)狀態(tài)。
- 死亡(DEAD):線程run()、main() 方法執(zhí)行結(jié)束,或者因異常退出了run()方法,則該線程結(jié)束生命周期。死亡的線程不可再次復(fù)生。
一.線程的狀態(tài)圖

二.初始狀態(tài)
- 實(shí)現(xiàn)Runnable接口和繼承Thread可以得到一個(gè)線程類(lèi),new一個(gè)實(shí)例出來(lái),線程就進(jìn)入了初始狀態(tài)
三.可運(yùn)行狀態(tài)
- 可運(yùn)行狀態(tài)只是說(shuō)你資格運(yùn)行,調(diào)度程序沒(méi)有挑選到你,你就永遠(yuǎn)是可運(yùn)行狀態(tài)。
- 調(diào)用線程的start()方法,此線程進(jìn)入可運(yùn)行狀態(tài)。
- 當(dāng)前線程sleep()方法結(jié)束,其他線程join()結(jié)束,等待用戶(hù)輸入完畢,某個(gè)線程拿到對(duì)象鎖,這些線程也將進(jìn)入可運(yùn)行狀態(tài)。
- 當(dāng)前線程時(shí)間片用完了,調(diào)用當(dāng)前線程的yield()方法,當(dāng)前線程進(jìn)入可運(yùn)行狀態(tài)。
- 鎖池里的線程拿到對(duì)象鎖后,進(jìn)入可運(yùn)行狀態(tài)。
四.運(yùn)行狀態(tài)
- 線程調(diào)度程序從可運(yùn)行池中選擇一個(gè)線程作為當(dāng)前線程時(shí)線程所處的狀態(tài)。這也是線程進(jìn)入運(yùn)行狀態(tài)的唯一一種方式。
五.死亡狀態(tài)
- 當(dāng)線程的run()方法完成時(shí),或者主線程的main()方法完成時(shí),我們就認(rèn)為它死去。這個(gè)線程對(duì)象也許是活的,但是,它已經(jīng)不是一個(gè)單獨(dú)執(zhí)行的線程。線程一旦死亡,就不能復(fù)生。
- 在一個(gè)死去的線程上調(diào)用start()方法,會(huì)拋出java.lang.IllegalThreadStateException異常。
六.阻塞狀態(tài)
- 當(dāng)前線程T調(diào)用Thread.sleep()方法,當(dāng)前線程進(jìn)入阻塞狀態(tài)。
- 運(yùn)行在當(dāng)前線程里的其它線程t2調(diào)用join()方法,當(dāng)前線程進(jìn)入阻塞狀態(tài)。
- 等待用戶(hù)輸入的時(shí)候,當(dāng)前線程進(jìn)入阻塞狀態(tài)。
七.等待隊(duì)列(本是Object里的方法,但影響了線程)
- 調(diào)用obj的wait(), notify()方法前,必須獲得obj鎖,也就是必須寫(xiě)在synchronized(obj) 代碼段內(nèi)。
- 與等待隊(duì)列相關(guān)的步驟和圖
- 線程1獲取對(duì)象A的鎖,正在使用對(duì)象A。
- 線程1調(diào)用對(duì)象A的wait()方法。
- 線程1釋放對(duì)象A的鎖,并馬上進(jìn)入等待隊(duì)列。
- 鎖池里面的對(duì)象爭(zhēng)搶對(duì)象A的鎖。
- 線程5獲得對(duì)象A的鎖,進(jìn)入synchronized塊,使用對(duì)象A。
- 線程5調(diào)用對(duì)象A的notifyAll()方法,喚醒所有線程,所有線程進(jìn)入鎖池。||||| 線程5調(diào)用對(duì)象A的notify()方法,喚醒一個(gè)線程,不知道會(huì)喚醒誰(shuí),被喚醒的那個(gè)線程進(jìn)入鎖池。
- notifyAll()方法所在synchronized結(jié)束,線程5釋放對(duì)象A的鎖。
-
鎖池里面的線程爭(zhēng)搶對(duì)象鎖,但線程1什么時(shí)候能搶到就不知道了。||||| 原本鎖池+第6步被喚醒的線程一起爭(zhēng)搶對(duì)象鎖。
等待隊(duì)列
八.鎖池狀態(tài)
- 當(dāng)前線程想調(diào)用對(duì)象A的同步方法時(shí),發(fā)現(xiàn)對(duì)象A的鎖被別的線程占有,此時(shí)當(dāng)前線程進(jìn)入鎖池狀態(tài)。簡(jiǎn)言之,鎖池里面放的都是想爭(zhēng)奪對(duì)象鎖的線程。
- 當(dāng)一個(gè)線程1被另外一個(gè)線程2喚醒時(shí),1線程進(jìn)入鎖池狀態(tài),去爭(zhēng)奪對(duì)象鎖。
- 鎖池是在同步的環(huán)境下才有的概念,一個(gè)對(duì)象對(duì)應(yīng)一個(gè)鎖池。
九.幾個(gè)方法的比較
- Thread.sleep(long millis),一定是當(dāng)前線程調(diào)用此方法,當(dāng)前線程進(jìn)入阻塞,但不釋放對(duì)象鎖,millis后線程自動(dòng)蘇醒進(jìn)入可運(yùn)行狀態(tài)。作用:給其它線程執(zhí)行機(jī)會(huì)的最佳方式。
- Thread.yield(),一定是當(dāng)前線程調(diào)用此方法,當(dāng)前線程放棄獲取的cpu時(shí)間片,由運(yùn)行狀態(tài)變會(huì)可運(yùn)行狀態(tài),讓OS再次選擇線程。作用:讓相同優(yōu)先級(jí)的線程輪流執(zhí)行,但并不保證一定會(huì)輪流執(zhí)行。實(shí)際中無(wú)法保證yield()達(dá)到讓步目的,因?yàn)樽尣降木€程還有可能被線程調(diào)度程序再次選中。Thread.yield()不會(huì)導(dǎo)致阻塞。
- t.join()/t.join(long millis),當(dāng)前線程里調(diào)用其它線程1的join方法,當(dāng)前線程阻塞,但不釋放對(duì)象鎖,直到線程1執(zhí)行完畢或者millis時(shí)間到,當(dāng)前線程進(jìn)入可運(yùn)行狀態(tài)。
- obj.wait(),當(dāng)前線程調(diào)用對(duì)象的wait()方法,當(dāng)前線程釋放對(duì)象鎖,進(jìn)入等待隊(duì)列。依靠notify()/notifyAll()喚醒或者wait(long timeout)timeout時(shí)間到自動(dòng)喚醒。
- obj.notify()喚醒在此對(duì)象監(jiān)視器上等待的單個(gè)線程,選擇是任意性的。notifyAll()喚醒在此對(duì)象監(jiān)視器上等待的所有線程。
