Java 線程:Java線程的生命周期

通用的線程生命周期

  • 五態模型: 初始狀態、可運行狀態、運行狀態、休眠狀態、終止狀態
  1. 初始狀態:指的線程已經被創建,但是還不允許分配的CPU執行。僅僅只編程語言層面被創建,而在操作系統層面,真正的線程還沒有創建。
  2. 可運行狀態: 指的是線程可以分配CPU執行。此時操作系統線程已經被成功創建了,所以可以分配CPU執行。
  3. 當有空間CPU時,操作系統會將其分配給一個處于可運行狀態的線程。被分配到CPU的線程的狀態就轉換成了運行狀態。
  4. 運行狀態的線程如果調用一個阻塞API或者等待某個事件,此時線程的狀態就會轉換到了休眠狀態,同時釋放CPU使用權,休眠狀態的線程永遠沒有機會獲得CPU使用權。當等待的時間出現了,線程就會從休眠狀態轉換到可運行狀態。
  5. 線程執行完或者出現異常就會進入終止狀態。就行終止狀態也就意味著線程的生命周期結束了

Java中線程的生命周期

  1. NEW(初始化狀態)
  2. RUNNABLE(可運行/運行狀態)
  3. BLOCKED(阻塞狀態)
  4. WAITING(無時限等待)
  5. TERMINATED(終止狀態)

各個狀態的轉換:

  1. RUNNABLE與BLOCKED狀態轉換
  • synchronized
  1. RUNNABLE與WAITING的狀態轉換
  • 有三種場景會觸發轉換:

    1. 獲得synchronized 隱式鎖的線程,調用了無參數的Object.wait()方法
    2. 調用了Thread.join()方法。其中join()是一種線程同步方法,例如一個線程Thread A,當調用A.join()的時候,執行這條語句的線程會等待thread A執行完,而等待中的這個線程,其狀態會從RUNNABLE轉換到WAITING.當線程thread A執行完,原來等待它的線程又從WAITING狀態裝換到RUNNABLE。
    3. LockSupport.park()方法。java并發包中的鎖,都是基于LockSupport對象實現的。調用LockSupport()方法,當前線程會阻塞,線程的狀態會從RUNNABLE轉換到WAITING。調用LockSupport.unpark(Thread thread)可喚醒目標線程,目標線程的狀態又從WAITING狀態轉換到RUNNABLE。
  1. RUNNABLE與TIMED_WAITING的狀態轉換
  • 五種場景觸發這種轉換:
    1. 調用帶超時參數的Thread.sleep(long millis)方法
    2. 獲得synchronized隱式鎖的線程,調用帶超時參數的Object.wait(long timeout)方法
    3. 調用帶超時參數的Thead.join(long millis)方法
    4. 調用帶超時參數的LockSupport.parkNanos(Object blocker,long deadline)方法
    5. 調用帶超時參數的LockSupport.parkUntil(long deadline)方法。
  1. 從NEW到RUNNABLE狀態
  • 兩種創建線程的方式
  • 當線程被NEW出來以后,調用start()后才會從NEW轉換到RUNNABLE
  1. 從RUNNABLE 到 TERMINATED狀態
  • 線程執行完run()方法后,會自動轉換到TERMINATED狀態,當如果執行run()方法時拋出異常,也會線程終止
  1. stop()和interrupt()方法的主要區別?
    1. stop():stop()方法會真的殺死線程,不給線程喘息的機會,如果線程持有ReentrantLock鎖,被stop()的線程并不會自動調用ReentrantLock的unlock()去釋放鎖,那其他線程就再也沒有機會獲得ReentrantLock鎖,這很危險。所以stop()/suspend()/resume()方法,都不建議使用
    2. interrput():interrupt()方法僅僅是通知線程,線程有機會執行一些后續的操作,同時也可以無視這個通知。被interrupt的線程,是怎么收到通知的呢?一種是異常,另一種是主動檢測。
    • 異常:

      1. 當線程A處于WAITING、TIMED_WAITING狀態時,如果其他線程調用線程A的interrupt()方法,會使線程A返回RUNNABLE狀態,同時線程A的代碼會觸發InterruptedException異常。WAITING、TIMED_WAITING狀態的觸發條件都是調用了類似wait()、join()、sleep()這樣的方法,這些方法的簽名,發現都會throws InterruptedException這個異常。這個異常的觸發條件就是:其他線程調用了該線程的interrupt()方法.
      2. 當線程A處于RUNNABLE狀態,并且阻塞在java.nio.channels.InterruptibleChannedl上時,如果其他線程調用線程A的interrupt()方法,線程A會觸發java.nio.channels.ClosedByInterruptExecption這個異常;而阻塞在java.nio.channels.Selector上時,如果其他線程調用A的interrupt()方法,線程A的java.nio.channels.Selector會立即返回。
    • 主動檢測:
      如果線程處于RUNNABLE狀態,并且沒有阻塞在某個I/O操作上,,例如中斷就散圓周率的線程A,這時就得依賴A主動檢測人中斷狀態了。如果其他線程調用了A的interrupt()方法,那么線程A可以通過isInterrupt()方法,檢測是不是自己中斷了。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容