新聞中心
本文轉(zhuǎn)載自微信公眾號(hào)「 Java極客技術(shù)」,作者鴨血粉絲 。轉(zhuǎn)載本文請(qǐng)聯(lián)系Java極客技術(shù)公眾號(hào)。

創(chuàng)新互聯(lián)建站是一家集成都網(wǎng)站制作、成都做網(wǎng)站、網(wǎng)站頁(yè)面設(shè)計(jì)、網(wǎng)站優(yōu)化SEO優(yōu)化為一體的專業(yè)網(wǎng)站制作公司,已為成都等多地近百家企業(yè)提供網(wǎng)站建設(shè)服務(wù)。追求良好的瀏覽體驗(yàn),以探求精品塑造與理念升華,設(shè)計(jì)最適合用戶的網(wǎng)站頁(yè)面。 合作只是第一步,服務(wù)才是根本,我們始終堅(jiān)持講誠(chéng)信,負(fù)責(zé)任的原則,為您進(jìn)行細(xì)心、貼心、認(rèn)真的服務(wù),與眾多客戶在蓬勃發(fā)展的市場(chǎng)環(huán)境中,互促共生。
面試官:你不是精通 Java 并發(fā)嗎?從基礎(chǔ)的 Java 線程生命周期開始講講吧。
好的,面試官。吧啦啦啦...
如果要說 Java 線程的生命周期的話,那我覺得就要先說說操作系統(tǒng)的線程生命周期
因?yàn)?JVM 是跑在操作系統(tǒng)上面的嘛,所以是繞不過去的,而且可以說, Java 語言中的線程本質(zhì)上就是操作系統(tǒng)的線程
聰明的你肯定也發(fā)現(xiàn)了,不管是操作系統(tǒng),還是 Java 或者 C# 都有線程的概念。在它們之間,關(guān)于線程的生命周期這一部分,肯定是有相同之處的,否則的話,操作系統(tǒng)自己一套生命周期流程, Java 又有自己的一套, C# 又有自己的一套,而且相互之間還要能夠互相配合,這種成本想想就大的不行對(duì)吧
所以咱們就來看看,通用的線程生命周期都有啥
先直接上張圖(阿粉這次的圖,可還行?):
可以看到,主要有 new , ready , running , waiting , terminated 5 種狀態(tài)
其中:
- new 只是說,這個(gè)線程被創(chuàng)建了,但是還不允許分配 CPU 執(zhí)行。因?yàn)檫@個(gè)狀態(tài)只是說明你在編程語言層面被創(chuàng)建了,操作系統(tǒng)層面還沒有被創(chuàng)建,肯定就談不上分配 CPU 執(zhí)行了
- ready 這個(gè)狀態(tài)是說,在操作系統(tǒng)層面已經(jīng)成功創(chuàng)建了,所以接下來就是等待分配 CPU 執(zhí)行了。還記得那句經(jīng)典的嘛?ready ?go !
- running 的狀態(tài),相信你就知道了,我都已經(jīng) ready 了,此時(shí)如果再給我分配一下 CPU 我是不是就可以 go 了?那不就是 running 狀態(tài)了嘛
- waiting 狀態(tài),就是線程在 running 狀態(tài)的時(shí)候,突然發(fā)現(xiàn),哎,我需要進(jìn)行一下 I/O 操作,或者需要等待某個(gè)事件發(fā)生(比如說需要某個(gè)條件變量),這個(gè)時(shí)候是不是就不能再繼續(xù) happy 的 running 了。那咋辦?waiting 一下唄
- 那你都 waiting 了,占用的 CPU 資源是不是應(yīng)該釋放掉?所以說, waiting 狀態(tài)的線程是永遠(yuǎn)沒有機(jī)會(huì)獲得 CPU 使用權(quán)的
- 你是不是一聽「永遠(yuǎn)沒有機(jī)會(huì)」這幾個(gè)字就給嚇壞了,我該不會(huì)永遠(yuǎn)沒有機(jī)會(huì)執(zhí)行了吧。放心吧,你不是在 waiting 嘛,等你 wait 的事件發(fā)生了,就可以繼續(xù)到 running 狀態(tài)
- 當(dāng)整個(gè)線程執(zhí)行完畢,或者出現(xiàn)異常的時(shí)候,就進(jìn)入了 terminated 狀態(tài),也就是線程的使命就完成啦,處于 terminated 狀態(tài)的線程不會(huì)再切換到其他狀態(tài)了
通用的線程生命周期以及它們之間是如何切換的,到這里,應(yīng)該就比較清楚了
接下來咱們看看 Java 線程的生命周期,在這個(gè)基礎(chǔ)上是怎么做的優(yōu)化,有什么區(qū)別
Java 線程的生命周期
咱們先來瞅瞅源碼定義的狀態(tài)(為了突出重點(diǎn),我把注釋都去掉了):
- public enum State {
- NEW,
- RUNNABLE,
- BLOCKED,
- WAITING,
- TIMED_WAITING,
- TERMINATED;
- }
能夠清楚的看到,在源碼中定義了 6 種線程狀態(tài),剛才的通用狀態(tài)有幾種來著?5 種對(duì)吧,現(xiàn)在是 6 種。
這 6 種是干啥的?剛才的 5 種狀態(tài)以及它們之間的切換我搞清楚了,這 6 種狀態(tài)它們之間又是怎么切換的呢?
別急,阿粉這么貼心,肯定也是畫好了一張圖的:
這 6 個(gè)狀態(tài)咱們也是分別來看:
- NEW 到 RUNNABLE ,應(yīng)該是挺容易理解的,就是 thread 調(diào)用了 start 方法
- Java 剛創(chuàng)建出來的 Thread 對(duì)象就是 NEW 狀態(tài),創(chuàng)建 Thread 對(duì)象主要有兩種方法,一種是繼承 Thread 對(duì)象,重寫 run() 方法,一種是實(shí)現(xiàn) Runnable 接口,重寫 run() 方法,并將該實(shí)現(xiàn)類作為創(chuàng)建 Thread 對(duì)象的參數(shù)
- 但是還記得嘛, NEW 只是說,這個(gè)線程在編程語言層面創(chuàng)建了,在操作系統(tǒng)層面還沒有創(chuàng)建,那當(dāng)然就不會(huì)被操作系統(tǒng)調(diào)度了對(duì)不對(duì),就更談不上執(zhí)行了
- 所以 Java 線程如果想要執(zhí)行的話,就必須轉(zhuǎn)換到 RUNNABLE 狀態(tài),也就是 thread 調(diào)用 start 方法
- RUNNABLE 與 BLOCKED ,如果線程等待 synchronized 的隱式鎖時(shí),就會(huì)從 RUNNABLE 狀態(tài)轉(zhuǎn)到 BLOCKED 狀態(tài)。因?yàn)?synchronized 修飾的方法/代碼塊同一時(shí)刻只允許一個(gè)線程執(zhí)行,所以其他線程就只能等待了唄,當(dāng)?shù)却木€程獲得 synchronized 隱式鎖時(shí),就會(huì)從 BLOCKED 狀態(tài)轉(zhuǎn)到 RUNNABLE 狀態(tài)
- 在這里有沒有個(gè)疑問?就是線程在 wait 一個(gè)條件發(fā)生時(shí),在操作系統(tǒng)層面線程會(huì)轉(zhuǎn)到 waiting 狀態(tài),那么在 JVM 層面呢?在 JVM 層面, Java 線程狀態(tài)是不會(huì)發(fā)生變化的。也就是這個(gè)時(shí)候 Java 線程的狀態(tài)依然是 RUNNABLE 狀態(tài)
- RUNNABLE 與 WAITING 狀態(tài)轉(zhuǎn)換,我感覺圖已經(jīng)說得很好了,在這里不再贅述
- RUNNABLE 與 TIMED_WAITING 狀態(tài)轉(zhuǎn)換,我感覺圖已經(jīng)說得很好了,在這里也不再贅述,仔細(xì)觀察下會(huì)發(fā)現(xiàn), TIMED_WAITING 與 WAITING 相比,就是多了超時(shí)參數(shù),畢竟 TIMED_WAITING 是有時(shí)限等待嘛
- RUNNABLE 到 TERMINATED ,這個(gè)過程比較好理解,線程執(zhí)行完 run() 方法之后,就自動(dòng)到 TERMINATED 狀態(tài)了,當(dāng)然了如果在執(zhí)行 run() 方法過程中有異常拋出,也會(huì)導(dǎo)致線程終止
- 有時(shí)候我們可能需要強(qiáng)制中斷 run() 方法的執(zhí)行,怎么辦呢?是使用 stop() 方法還是 interrupt() 方法呢?正確的姿勢(shì)是調(diào)用 interrupt() 方法
- stop() 方法會(huì)真的殺死線程,不給線程一點(diǎn)兒喘息的機(jī)會(huì),如果被殺死的線程持有 synchronized 隱式鎖,那就再也不會(huì)釋放掉這個(gè)鎖了,接下來的線程也就沒辦法獲得 synchronized 隱式鎖,是不是特別危險(xiǎn)?同樣 suspend() 和 resume() 這兩個(gè)方法也是不建議使用
- interrupt() 方法相比于 stop() 方法就溫柔很多,它只是通知線程后續(xù)的操作可以不用去執(zhí)行了,線程可以選擇執(zhí)行現(xiàn)在就不執(zhí)行,當(dāng)然也可以選擇再執(zhí)行一段時(shí)間后再停止,或者我就不聽你的,非要執(zhí)行完,都沒關(guān)系, interrupt() 只是通知一下你而已。就比如你要做火車去一個(gè)地方,突然通知你這個(gè)火車晚點(diǎn)了,你可以選擇無視這個(gè)通知繼續(xù)等待,或者選擇另外一趟高鐵,但是不管你做什么,和火車站都沒啥關(guān)系,它通知的責(zé)任盡到了
看到這里應(yīng)該就比較清楚了吧
在 Java 線程生命周期中, RUNNABLE 狀態(tài)是將 ready 和 running 兩種狀態(tài)合并在了一起,而 BLOCKED , WAITING , TIMED_WAITING 這三種狀態(tài)其實(shí)就是 waiting 狀態(tài),也就是線程要等待某些事件發(fā)生,才能繼續(xù)向下執(zhí)行下去
關(guān)于 Java 線程的生命周期,到這里就說完啦
畫個(gè)圖 + 講解,和面試官扯半小時(shí)應(yīng)該沒問題吧?
網(wǎng)頁(yè)標(biāo)題:面試官?zèng)]想到,一個(gè)Java線程生命周期,我可以扯半小時(shí)
文章轉(zhuǎn)載:http://www.dlmjj.cn/article/cdpjjoe.html


咨詢
建站咨詢
