工做三年,小胖竟然問我線程有多少種狀態?真的菜!

哈嘍,你們好,我是狗哥。很久沒有更新原創文章了。主要是由於今年上半年這段時間都在忙着運營個人小號:上路的狗哥,主要分享一些職場以及生活中的高效又有趣的工具,好比:某度網盤提速工具、免費的 OCR 識別工具、免費聽全網音樂的 APP 以及免費看全網影視的 APP 等等,感興趣的能夠關注一下。前端

通過半年的運營,小號在徹底零推廣的狀況下累計了 1.3W 鐵粉。爲何忽然又更新技術原創文章了?主要是由於寫代碼纔是個人主業,公衆號只是我的興趣。作事不能本末倒置,因此決定之後仍是要周更這個技術公衆號。java

線程有哪 6 種狀態?

人有生老病死。一樣的,線程有本身的生命週期。在 Java 中線程的生命週期中一共有 6 種狀態:面試

  • New(新建立)
  • Runnable(可運行)
  • Blocked(被阻塞)
  • Waiting(等待)
  • Timed Waiting(計時等待)
  • Terminated(被終止)

查看 Thread 類的源碼時,內部還定義了這樣一個枚舉類。這個枚舉類定義的就是線程的狀態,源碼以下:算法

public enum State {
       
        NEW,

        RUNNABLE,

        BLOCKED,

        WAITING,

        TIMED_WAITING,

        TERMINATED;
}

PS:線程在任什麼時候刻只可能處於以上 6 種的其中 1 種狀態,咱們能夠調用 getState() 查看線程的狀態數據庫

線程是如何切換狀態的?

咱們知道線程有 6 種狀態。然而,它是如何切換的呢?狗哥根據本身的理解作了一張圖,接下來將根據這張圖詳細瞭解下線程狀態的切換。編程

線程的 6 種狀態

NEW(新建立)

先注意 NEW 狀態:線程被 NEW 出來,但還沒調用 start 方法時,就處於這種狀態。一旦調用了 start 方法也就進入了 RUNNABLE 狀態。設計模式

RUNNABLE(可運行)

處於 RUNNABLE 的線程,比較特殊。它還分兩種狀態:Running 和 Ready。也就是說,Java 中處於 Runnable 狀態的線程有可能正在執行,也有可能沒有正在執行,正在等待被分配 CPU 資源微信

所以,咱們能夠推斷出,一個處於 Runnable 狀態的線程,當它運行到任務的一半時,執行該線程的 CPU 被調度去作其餘事情,則該線程暫時不運行。可是,它的狀態依然不變,仍是 Runnable,由於它有可能隨時被調度回來繼續執行任務數據結構

也就是說:處於 Runnable 狀態的線程並不必定在運行。這點在面試中常問,小夥伴們要注意了。併發

Blocked(被阻塞)

再來看看最簡單的 Blocked 狀態,從 Runnable 進入 Blocked 只有一種可能:就是進入 synchronized 關鍵字保護的代碼,可是沒有獲取到 monitor 鎖

線程的 6 種狀態

再來,看圖的右側,Blocked ----> Runnable 狀態:當處於 Blocked 狀態的線程獲取到鎖

Waiting (等待)

線程從 Runnable 進入 Blocked 狀態,有三種可能性:

  • 沒有設置 Timeout 參數的 Object.wait () 方法。
  • 沒有設置 Timeout 參數的 Thread.join () 方法。
  • LockSupport.park () 方法。

上面咱們知道,線程進入 Blocked 狀態只多是:進入 synchronized 保護的代碼,可是沒獲取到 monitor 鎖。然而,Java 中還有不少鎖,好比:ReentrantLock。線程在獲取這種鎖時,沒有搶到就會進入 Waiting 狀態,由於它本質上是調用了 LockSupport.park () 方法。

一樣的,調用 Object.wait () 和 Thread.join () 也會讓線程進入等待狀態

Blocked 與 Waiting 的區別是:Blocked 在等待其餘線程釋放 monitor 鎖,而 Waiting 則是在等待某個條件,好比 join 的線程執行完畢,或者是 notify ()/notifyAll ()

線程的 6 種狀態

看 Waiting 右側,Waiting ----> Runnable:一、當執行了 LockSupport.unpark (),二、join 的線程運行結束,三、被中斷

看 Waiting 右側,Waiting ----> Blocked:咱們看圖能夠知道其餘線程調用 notify () 或 notifyAll () 來喚醒處於 Waiting 的線程,它會直接進入 Blocked 狀態。這是爲何?

其餘線程能調用 notify () 或 notifyAll () 試圖喚醒 Waiting 狀態線程,說明必須持有同一個 monitor 鎖,也就是說處於 Waiting 的線程被喚醒後並不能立刻搶到 monitor 鎖,因此它必須先進入 Blocked 狀態。而喚醒它的線程執行完畢釋放鎖後,它能搶到鎖就從 Blocked 進入 Runnable 狀態

Timed Waiting(計時等待)

這種狀態與 Waiting 狀態的區別在於:有沒有時間限制,Timed Waiting 會等待超時,由系統自動喚醒,或者在超時前被喚醒信號喚醒

有如下 5 種狀況會讓線程進入 Timed Waiting 狀態:

  • 設置 Timeout 參數的 Thread.sleep (time) 方法。
  • 設置 Timeout 參數的 Object.wait (time) 方法。
  • 設置 Timeout 參數的 Thread.join (time) 方法。
  • 設置 Timeout 參數的 LockSupport.parkNanos (long nanos) 方法。
  • 設置 Timeout 參數的 LockSupport.parkUntil (long deadline) 方法。

線程的 6 種狀態

看 Timed Waiting 右側,Timed Waiting ----> Blocked:跟 Waiting 同樣,其餘線程執行 notify () 和 notifyAll (),當前線程也是先進入 Blocked 狀態,然後視鎖的獲取狀況再決定是否進入 Runnable 狀態。

另外,Timed Waiting ----> Runnable :一、當前線程的超時時間到了且能直接獲取到鎖,二、join 的線程運行結束,三、被中斷,四、調用了 LockSupport.unpark (),這幾種狀況會直接恢復到 Runnable,而無需經歷 Blocked 狀態。

Terminated(被終止)

最後一種,想要進入終止狀態就比較簡單了,有三種狀況:

  • 任務執行完畢,線程正常退出。
  • 出現一個沒有捕獲的異常(好比直接調用 interrupt() 方法)。

總結

  • 線程的狀態是須要按照箭頭方向走,好比線程從 New 狀態是不能夠直接進入 Blocked 狀態的,它須要先經歷 Runnable 狀態。
  • 線程生命週期不可逆:一旦進入 Runnable 狀態就不能回到 New 狀態;一旦被終止就不可能再有任何狀態的變化。因此一個線程只能有一次 New 和 Terminated 狀態,只有處於中間狀態才能夠相互轉換

巨人的肩膀

  • Java 併發編程 78 講 — 徐隆曦

福利

若是看到這裏,喜歡這篇文章的話,請幫點個好看。微信搜索一個優秀的廢人,關注後回覆電子書送你 100+ 本編程電子書 ,不僅 Java 哦,詳情看下圖。回覆 1024送你一套完整的 java 視頻教程。

資源

C語言

C++

Java

Git

Python

GO

Linux

經典必讀

面試相關

前端

人工智能

設計模式

數據庫

數據結構與算法

計算機基礎

一個優秀的廢人

相關文章
相關標籤/搜索