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é)束趁怔,等待用戶輸入完畢湿硝,某個(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)续扔。
- 等待用戶輸入的時(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)視器上等待的所有線程仍劈。