图解 Java 线程的生命周期,看完再也不怕面试官问了
文章首發自個人微信公眾號: 小哈學Java
www.exception.site/java-concur…
在 Java 初中級面試中,關于線程的生命周期可以說是??土?。本文就針對這個問題,通過圖文并茂的方式詳細說說。
java線程生命周期結合上圖,線程的生命周期大致可分為以下五種狀態:
- NEW - 新建
- RUNNABLE - 等待被CPU調度
- RUNNING - 正在運行
- BLOCKED - 阻塞
- TERMINATED - 結束
一、NEW 狀態
NEW 狀態表示線程被新建的狀態,我們來看一段示例代碼:
Thread thread = new Thread(() -> System.out.println("Hello, world !")); 復制代碼當我們在代碼中 new 一個 Thread 的時候,就代表著 thread 線程處于 NEW 狀態了,但是此時該線程還未被操作系統創建出來,只有當我們調用了 start() 方法之后,該線程才會被創建出來。所以準確來說,NEW 狀態只是線程對象的狀態。
NEW 狀態的線程能發生哪些狀態轉變?
new狀態線程能夠發生的狀態轉換NEW 狀態的線程在調用 start() 方法后,進入 RUNNABLE 狀態。
二、RUNNABLE 狀態
當我們在代碼中顯式的調用 start() 方法后,JVM 進程會去創建一個新的線程,而此線程不會馬上被 CPU 調度運行,進入 RUNNING 狀態,這里會有一個中間狀態,就是 RUNNABLE 狀態,你可以理解為等待被 CPU 調度的狀態:
RUNNABLE中間狀態如上圖所示,也就是說線程會從 NEW 狀態 -> RUNNABLE 狀態 ,等待 CPU 調度,再大白話一點,就是說這種線程具備被執行的資格,但是能否進入執行階段,還得看 CPU 的臉色說話。
RUNNABLE 狀態的線程能發生哪些狀態轉變?
runnable狀態轉換RUNNABLE 狀態的線程無法直接進入 BLOCKED 狀態和 TERMINATED 狀態的。
很多小伙伴這里可能有疑問,為啥呢?
只有處在 RUNNING 狀態的線程,換句話說,只有獲得 CPU 調度執行權的線程才有資格進入 BLOCKED 狀態和 TERMINATED 狀態
PS: RUNNABLE 狀態的線程要么能被轉換成 RUNNING 狀態,要么被意外終止(如 kill -9 PID)。
三、RUNNING 狀態
當 CPU 調度發生,并任務隊列中選中了某個 RUNNABLE 線程時,該線程會進入 RUNNING 執行狀態,并且開始調用 run()方法中邏輯代碼。
RUNNING 狀態的線程能發生哪些狀態轉變?
RUNNING狀態轉換- 被轉換成 TERMINATED 狀態,比如調用 stop() 方法;
- 被轉換成 BLOCKED 狀態,比如調用了sleep, wait 方法被加入 waitSet 中;
- 被轉換成 BLOCKED 狀態,如進行 IO 阻塞操作,如查詢數據庫進入阻塞狀態;
- 被轉換成 BLOCKED 狀態,比如獲取某個鎖的釋放,而被加入該鎖的阻塞隊列中;
- 該線程的時間片用完,CPU 再次調度,進入 RUNNABLE 狀態;
- 線程主動調用 yield 方法,讓出 CPU 資源,進入 RUNNABLE 狀態;
四、BLOCKED 狀態
上小節中我們已經講到了,進入 BLOCKED 原因,這里,我們就直接談談 BLOCK 狀態的線程能夠發生哪些狀態改變:
BLOCKED狀態轉換- 被轉換成 TERMINATED 狀態,比如調用 stop() 方法,或者是 JVM 意外 Crash;
- 被轉換成 RUNNABLE 狀態,阻塞時間結束,比如讀取到了數據庫的數據后;
- 完成了指定時間的休眠,進入到 RUNNABLE 狀態;
- 正在 wait 中的線程,被其他線程調用 notify/notifyAll 方法喚醒,進入到 RUNNABLE 狀態;
- 線程獲取到了想要的鎖資源,進入 RUNNABLE 狀態;
- 線程在阻塞狀態下被打斷,如其他線程調用了 interrupt 方法,進入到 RUNNABLE 狀態;
五、TERMINATED 狀態
TERMINATED 狀態是線程的最終狀態,處于此狀態中的線程不會切換到以上任何狀態,一旦線程進入了 TERMINATED 狀態,就意味著這個線程生命的終結,沒有回頭路了。
以下情況下,線程會進入到 TERMINATED 狀態:
- 線程正常運行結束,生命周期結束;
- 線程運行過程中出現意外錯誤;
- JVM 異常結束,所有的線程生命周期均被結束。
六、start 方法源碼解析,何時調用的 run() 方法?
通過圖文,我們了解了線程生命周期的五種狀態,接下來,我們來看看 start 方法源碼,其實內部的源碼非常簡單,如下圖所示:
start方法內部源碼- ①:首先,會判斷線程的狀態是否是 NEW 狀態,內部對應的狀態標識是個 0,也就是說如果不等于 0,直接拋線程狀態異常;
- ②:線程在啟動后被加入到 ThreadGroup 中;
- ③: start0 是最核心的方法了,就是運行狀態為 NEW (內部狀態標識為 0) 的線程;
- ④:start0 是個 native 方法,也就是 JNI 方法;
看到這里,你也許會有個疑問,自己重寫的 run 方法是什么時候被調用的呢?源碼中也沒看到調用啊!!
Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread.
上面這段截自 JDK 官方文檔,意思是說:
run 方法是在調用 JNI 方法 start0() 的時候被調用的,被調用后,我們寫的邏輯代碼才得以被執行。
一些面試中,面試官也會經常問到這個問題:線程的 start 方法和 run 方法有什么區別?
相信看完上面的源碼分析,小伙伴們一定可以源碼的角度懟回去了!
七、總結
本文中,小哈通過圖文的方式解釋了線程的五種狀態,以及各種狀態能夠被轉換的狀態。最后,我們簡單看了一下 start()內部源碼,知道了 run() 方法何時被執行的。最后,希望看完本文的小伙伴們能有所收獲,下期見!
八、Ref
- 《Java高并發編程詳解》
歡迎關注微信公眾號: 小哈學Java
小哈學Java贈送 | 面試&學習福利資源
最近在網上發現一個不錯的 PDF 資源《Java 核心面試知識.pdf》分享給大家,不光是面試,學習,你都值得擁有!!!
獲取方式: 關注微信公眾號: 小哈學Java, 后臺回復"資源",既可免費無套路獲取資源鏈接,下面是目錄以及部分截圖:
福利資源截圖 福利資源截圖 福利資源截圖 福利資源截圖 福利資源截圖 福利資源截圖 福利資源截圖重要的事情說兩遍,獲取方式: 關注微信公眾號: 小哈學Java, 后臺回復"資源",既可免費無套路獲取資源鏈接 !!!
轉載于:https://juejin.im/post/5cbd3df6f265da0363454d78
總結
以上是生活随笔為你收集整理的图解 Java 线程的生命周期,看完再也不怕面试官问了的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: KDE Applications 19.
- 下一篇: 设计模式之工厂模式(三)