哈嘍,你們好,我是狗哥。很久沒有更新原創文章了。主要是由於今年上半年這段時間都在忙着運營個人小號:上路的狗哥,主要分享一些職場以及生活中的高效又有趣的工具,好比:某度網盤提速工具、免費的 OCR 識別工具、免費聽全網音樂的 APP 以及免費看全網影視的 APP 等等,感興趣的能夠關注一下。前端
通過半年的運營,小號在徹底零推廣的狀況下累計了 1.3W 鐵粉。爲何忽然又更新技術原創文章了?主要是由於寫代碼纔是個人主業,公衆號只是我的興趣。作事不能本末倒置,因此決定之後仍是要周更這個技術公衆號。java
人有生老病死。一樣的,線程有本身的生命週期。在 Java 中線程的生命週期中一共有 6 種狀態:面試
查看 Thread 類的源碼時,內部還定義了這樣一個枚舉類。這個枚舉類定義的就是線程的狀態,源碼以下:算法
public enum State { NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED; }
PS:線程在任什麼時候刻只可能處於以上 6 種的其中 1 種狀態,咱們能夠調用 getState() 查看線程的狀態。數據庫
咱們知道線程有 6 種狀態。然而,它是如何切換的呢?狗哥根據本身的理解作了一張圖,接下來將根據這張圖詳細瞭解下線程狀態的切換。編程
先注意 NEW 狀態:線程被 NEW 出來,但還沒調用 start 方法時,就處於這種狀態。一旦調用了 start 方法也就進入了 RUNNABLE 狀態。設計模式
處於 RUNNABLE 的線程,比較特殊。它還分兩種狀態:Running 和 Ready。也就是說,Java 中處於 Runnable 狀態的線程有可能正在執行,也有可能沒有正在執行,正在等待被分配 CPU 資源。微信
所以,咱們能夠推斷出,一個處於 Runnable 狀態的線程,當它運行到任務的一半時,執行該線程的 CPU 被調度去作其餘事情,則該線程暫時不運行。可是,它的狀態依然不變,仍是 Runnable,由於它有可能隨時被調度回來繼續執行任務。數據結構
也就是說:處於 Runnable 狀態的線程並不必定在運行。這點在面試中常問,小夥伴們要注意了。併發
再來看看最簡單的 Blocked 狀態,從 Runnable 進入 Blocked 只有一種可能:就是進入 synchronized 關鍵字保護的代碼,可是沒有獲取到 monitor 鎖。
再來,看圖的右側,Blocked ----> Runnable 狀態:當處於 Blocked 狀態的線程獲取到鎖。
線程從 Runnable 進入 Blocked 狀態,有三種可能性:
上面咱們知道,線程進入 Blocked 狀態只多是:進入 synchronized 保護的代碼,可是沒獲取到 monitor 鎖。然而,Java 中還有不少鎖,好比:ReentrantLock。線程在獲取這種鎖時,沒有搶到就會進入 Waiting 狀態,由於它本質上是調用了 LockSupport.park () 方法。
一樣的,調用 Object.wait () 和 Thread.join () 也會讓線程進入等待狀態。
Blocked 與 Waiting 的區別是:Blocked 在等待其餘線程釋放 monitor 鎖,而 Waiting 則是在等待某個條件,好比 join 的線程執行完畢,或者是 notify ()/notifyAll ()。
看 Waiting 右側,Waiting ----> Runnable:一、當執行了 LockSupport.unpark (),二、join 的線程運行結束,三、被中斷
看 Waiting 右側,Waiting ----> Blocked:咱們看圖能夠知道其餘線程調用 notify () 或 notifyAll () 來喚醒處於 Waiting 的線程,它會直接進入 Blocked 狀態。這是爲何?
其餘線程能調用 notify () 或 notifyAll () 試圖喚醒 Waiting 狀態線程,說明必須持有同一個 monitor 鎖,也就是說處於 Waiting 的線程被喚醒後並不能立刻搶到 monitor 鎖,因此它必須先進入 Blocked 狀態。而喚醒它的線程執行完畢釋放鎖後,它能搶到鎖就從 Blocked 進入 Runnable 狀態。
這種狀態與 Waiting 狀態的區別在於:有沒有時間限制,Timed Waiting 會等待超時,由系統自動喚醒,或者在超時前被喚醒信號喚醒。
有如下 5 種狀況會讓線程進入 Timed Waiting 狀態:
看 Timed Waiting 右側,Timed Waiting ----> Blocked:跟 Waiting 同樣,其餘線程執行 notify () 和 notifyAll (),當前線程也是先進入 Blocked 狀態,然後視鎖的獲取狀況再決定是否進入 Runnable 狀態。
另外,Timed Waiting ----> Runnable :一、當前線程的超時時間到了且能直接獲取到鎖,二、join 的線程運行結束,三、被中斷,四、調用了 LockSupport.unpark (),這幾種狀況會直接恢復到 Runnable,而無需經歷 Blocked 狀態。
最後一種,想要進入終止狀態就比較簡單了,有三種狀況:
若是看到這裏,喜歡這篇文章的話,請幫點個好看。微信搜索一個優秀的廢人,關注後回覆電子書送你 100+ 本編程電子書 ,不僅 Java 哦,詳情看下圖。回覆 1024送你一套完整的 java 視頻教程。