圖解Java線程狀態(tài)轉(zhuǎn)行
大家好,我是阿星,好久不見,歡迎來到Java并發(fā)編程系列番外篇線程狀態(tài)轉(zhuǎn)換,內(nèi)容通俗易懂,請放心食用。
線程狀態(tài)
先來個開場四連問
Java線程狀態(tài)有幾個?Java線程狀態(tài)是如何轉(zhuǎn)換?Java線程狀態(tài)轉(zhuǎn)換什么情況會進入鎖的等待隊列?Java線程狀態(tài)轉(zhuǎn)換什么情況會進入鎖的同步隊列?
一提到Java線程狀態(tài),不少讀者立馬想到線程狀態(tài)轉(zhuǎn)換圖,但細想,印象又不深刻,只記得有那么幾個狀態(tài)。
再要你說出Java線程狀態(tài)是如何轉(zhuǎn)換的,腦子里可能就如下圖一樣,已經(jīng)是一團漿糊了。

別慌,阿星為了幫讀者大大們理清楚上面的問題,會一步一步的把線程狀態(tài)轉(zhuǎn)換圖給畫出來,讓讀者大大們真正的理解Java線程狀態(tài)轉(zhuǎn)換。
首先線程的狀態(tài)可以分為6態(tài)或7態(tài),具體狀態(tài)如下
6態(tài)
New:新建狀態(tài)Runnable:可運行狀態(tài)Terminated:終止狀態(tài)Waiting:等待狀態(tài)TimedWaiting:超時等待狀態(tài)Blocked:阻塞狀態(tài)
7態(tài)
New:新建狀態(tài)Ready:就緒狀態(tài)Running:運行狀態(tài)Terminated:終止狀態(tài)Waiting:等待狀態(tài)TimedWaiting:超時等待狀態(tài)Blocked:阻塞狀態(tài)
其實6態(tài)與7態(tài)差別不大,只不過7態(tài)把Runnable可運行狀態(tài),拆解成了Ready就緒狀態(tài)與Running運行狀態(tài)。
阿星以7態(tài)為例,來逐步講解它們之間是如何轉(zhuǎn)換的。
新建狀態(tài)(New)
我們可以通過實現(xiàn)Runnable接口或繼承Thread聲明一個線程類,new一個實例后,線程就進入了新建狀態(tài)。

一個剛誕生的線程,處于新建狀態(tài)。
就緒狀態(tài)(Ready)
線程對象創(chuàng)建成功后,調(diào)用該線程的start()函數(shù),線程進入就緒狀態(tài),該狀態(tài)的線程進入可運行線程池中,等待獲取C P U的使用權(quán)。

線程表示,我已經(jīng)準備好了,此時我是就緒狀態(tài),快選我吧~
運行狀態(tài)(Running)
此時線程調(diào)度程序正在從可運行線程池中選擇一個線程,該線程進入運行狀態(tài)。
換句話說,線程獲取到了C P U時間片。

還沒完呢,當線程時間片用完或調(diào)用的yield()函數(shù),該線程回到就緒狀態(tài)。

作為一名運氣好的線程,我進入了運行狀態(tài),但是運氣用完了,我還得回到就緒狀態(tài)。
終止狀態(tài)(Terminated)
線程繼續(xù)運行,直到執(zhí)行結(jié)束或執(zhí)行過程中因異常意外終止都會使線程進入終止狀態(tài)。
線程一旦終止,就不能復生,這是不可逆的過程。

線程的人生迎來了終點,可能一帆風順過完一生,也可能英年早逝令人惋惜。
等待狀態(tài)(Waiting)
運行狀態(tài)的線程執(zhí)行wait()、join()、LockSupport.park()任意函數(shù),該線程進入等待狀態(tài)。
其中wait()與join()函數(shù)會讓J V M把該線程放入鎖等待隊列。
處于這種狀態(tài)的線程不會被分配C P U執(zhí)行時間,它們要等待被主動喚醒,否則會一直處于等待狀態(tài)。

如果我們要喚醒線程怎么辦呢?
執(zhí)行LockSupport.unpark(t)函數(shù)喚醒指定線程,該線程回到就緒狀態(tài)。
而通過notify()、notifyAll()、join線程執(zhí)行完畢方式,會喚醒鎖等待隊列的線程,出隊的線程回到就緒狀態(tài)。

線程的人生迎來了劫難,聽信小人之言,跑去菲律賓做打工,結(jié)果被黑工廠扣下,只希望警察叔叔能早日解救我出去。
超時等待狀態(tài)(Timed waiting)
超時等待與等待狀態(tài)一樣,唯一的區(qū)別就是多了超時機制,不會一直等待被其他線程主動喚醒,而是到達指定時間后會自動喚醒。
以下函數(shù)會觸發(fā)進入超時等待狀態(tài)
wait(long) join(long) LockSupport.parkNanos(long) LockSupport.parkUtil(long) sleep(long)
其中wait(long)、join(long)函數(shù)會讓J V M把線程放入鎖等待隊列。

后面的喚醒劇情就和等待狀態(tài)如出一轍,就多了超時時間到了,自動喚醒的動作。

從菲律賓回國后的線程,也做起了違法的勾當,最終被警察抓捕,好在只判了5年,熬一熬就可以出來了。
阻塞狀態(tài)(Blocked)
運行狀態(tài)的線程獲取同步鎖失敗或發(fā)出I/O請求,該線程進入阻塞狀態(tài)。
如果是獲取同步鎖失敗J V M還會把該線程放入鎖的同步隊列。

同步鎖被釋放時,鎖的同步隊列會出隊所有線程,進入就緒狀態(tài)。
I/O處理完畢時,該線程重新回到就緒狀態(tài)。

出獄后的線程,后面的人生一直都是磕磕碰碰,就沒順利過,大家要引以為戒。
小結(jié)
相信讀者大大們跟著阿星的思路來,已經(jīng)掌握了線程狀態(tài)的知識,以后面試官問這類問題,也可以吊打一番,最后放一張簡化的線程轉(zhuǎn)換圖為本文畫上句號。

歷史好文推薦
圖文并茂的聊聊ReentrantReadWriteLock的位運算 通俗易懂的ReentrantLock,不懂你來砍我 萬字長文 | 16張圖解開AbstractQueuedSynchronizer 寫給小白看的LockSupport 13張圖,深入理解Synchronized 由淺入深CAS,小白也能與BAT面試官對線 小白也能看懂的Java內(nèi)存模型 保姆級教學,22張圖揭開ThreadLocal 進程、線程與協(xié)程傻傻分不清?一文帶你吃透! 什么是線程安全?一文帶你深入理解
關于我
阿星是一個熱愛技術的Java程序猿,公眾號 「程序猿阿星」 定期分享有趣有料的精品原創(chuàng)文章!

非常感謝各位小哥哥小姐姐們能看到這里,原創(chuàng)不易,文章有幫助可以關注、點個贊、分享與評論,都是支持(莫要白嫖)!
愿你我都能奔赴在各自想去的路上,我們下篇文章見。
