《線程狀態轉換深度解析:從阻塞到就緒的底層原理》

目錄

一、線程的五種基本狀態

二、線程從 RUNNABLE 進入阻塞 / 等待狀態的三種典型場景

1. 調用sleep(long millis):進入 TIMED_WAITING 狀態

2. 調用wait():進入 WAITING/TIMED_WAITING 狀態

3. 等待 I/O 資源或獲取鎖失敗:進入 BLOCKED 狀態

三、線程從阻塞 / 等待狀態回到 RUNNABLE 狀態的底層原理

1. TIMED_WAITING 狀態的喚醒(如sleep()超時)

2. WAITING/TIMED_WAITING 狀態的喚醒(如wait()被喚醒)

對象監視器(Monitor)

wait()方法的底層執行流程

notify()/notifyAll()的底層執行流程

3. BLOCKED 狀態的喚醒(如獲取鎖或 I/O 就緒)

四、總結:線程狀態轉換的核心邏輯


在多線程編程中,線程狀態的轉換是理解并發行為的核心。當運行中的線程因調用sleep()wait()或等待 I/O 等操作讓出 CPU 時,會進入特定的阻塞狀態;而從阻塞狀態重新回到可運行狀態的過程,更是體現了 JVM 對線程調度的精妙設計。本文將深入解析線程狀態轉換的底層機制,揭示線程如何在不同狀態間切換。

一、線程的五種基本狀態

根據 Java 線程模型,線程的生命周期包含五種狀態,由Thread.State枚舉定義:

  1. 新建(NEW):線程對象已創建但未調用start()方法。
  2. 可運行(RUNNABLE):線程已啟動,正在 JVM 中運行或等待 CPU 調度。
  3. 阻塞(BLOCKED):線程等待獲取 synchronized 鎖(進入 synchronized 塊 / 方法時未搶到鎖)。
  4. 等待(WAITING):線程無限期等待被其他線程喚醒(如調用wait()join()無參方法)。
  5. 超時等待(TIMED_WAITING):線程在指定時間內等待(如sleep(1000)wait(1000))。
  6. 終止(TERMINATED):線程執行完畢或因異常退出。

核心轉換場景:運行狀態(RUNNABLE)的線程會因特定操作進入阻塞 / 等待狀態,待條件滿足后重新回到 RUNNABLE 狀態。

二、線程從 RUNNABLE 進入阻塞 / 等待狀態的三種典型場景

運行中的線程(RUNNABLE)在以下情況會讓出 CPU,進入非運行狀態:

1. 調用sleep(long millis):進入 TIMED_WAITING 狀態

sleep()是 Thread 類的靜態方法,作用是讓當前線程暫停執行指定毫秒數。調用后線程狀態變化為:
RUNNABLE → TIMED_WAITING

  • 特點
    • 線程不會釋放已持有的鎖(如 synchronized 鎖)。
    • 暫停時間是相對精確的(受系統時鐘和 CPU 調度影響)。
    • 常用于模擬延遲(如網絡請求等待)。
public class SleepDemo {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(() -> {try {System.out.println("線程進入睡眠");Thread.sleep(3000); // 進入TIMED_WAITING狀態System.out.println("線程喚醒");} catch (InterruptedException e) {e.printStackTrace();}});t.start();}
}

2. 調用wait():進入 WAITING/TIMED_WAITING 狀態

wait()是 Object 類的方法,必須在synchronized塊中調用,作用是讓線程釋放鎖并等待被喚醒。調用后狀態變化為:
RUNNABLE → WAITING(無參wait())或TIMED_WAITINGwait(long timeout)

  • 特點
    • 必須持有對象鎖(synchronized),調用后立即釋放鎖。
    • 需其他線程調用同一對象的notify()/notifyAll()喚醒(或超時自動喚醒)。
    • 常用于線程間協作(如生產者消費者模型)。
public class WaitDemo {private static final Object lock = new Object();public static void main(String[] args) {new Thread(() -> {synchronized (lock) {try {System.out.println("線程進入等待");lock.wait(); // 進入WAITING狀態System.out.println("線程被喚醒");} catch (InterruptedException e) {e.printStackTrace();}}}).start();}
}

3. 等待 I/O 資源或獲取鎖失敗:進入 BLOCKED 狀態

當線程等待外部資源(如磁盤 IO、網絡請求)或嘗試獲取 synchronized 鎖但失敗時,會進入 BLOCKED 狀態:
RUNNABLE → BLOCKED

  • 特點
    • 等待 I/O 時,線程暫停執行,直到資源就緒(如數據讀取完成)。
    • 獲取鎖失敗時,線程進入鎖的 "入口集"(Entry Set)排隊,直到鎖被釋放。
public class BlockedDemo {private static final Object lock = new Object();public static void main(String[] args) {// 線程1先獲取鎖new Thread(() -> {synchronized (lock) {try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); }}}).start();// 線程2后啟動,嘗試獲取鎖失敗,進入BLOCKED狀態new Thread(() -> {synchronized (lock) { // 此處會阻塞System.out.println("線程2獲取到鎖");}}).start();}
}

三、線程從阻塞 / 等待狀態回到 RUNNABLE 狀態的底層原理

線程進入阻塞 / 等待狀態后,并非永久停止,而是在特定條件滿足后重新回到 RUNNABLE 狀態。不同狀態的喚醒機制底層原理不同:

1. TIMED_WAITING 狀態的喚醒(如sleep()超時)

sleep(long millis)的喚醒依賴系統定時器

  • 底層流程

    1. 線程調用sleep()時,JVM 向操作系統注冊一個定時事件(指定 millis 后觸發)。
    2. 線程從 RUNNABLE 狀態切換到 TIMED_WAITING,操作系統將其從 CPU 調度隊列中移除。
    3. 定時時間到達后,操作系統觸發事件,JVM 將線程重新放入 CPU 調度隊列,狀態切換為 RUNNABLE。
    4. 線程等待 CPU 調度,獲取時間片后繼續執行。
  • 特殊情況:若線程在sleep()期間被中斷(調用interrupt()),會拋出InterruptedException并提前喚醒,狀態直接回到 RUNNABLE。

2. WAITING/TIMED_WAITING 狀態的喚醒(如wait()被喚醒)

要理解wait()notify()/notifyAll()的底層原理,需要從線程狀態轉換對象監視器(Monitor)?兩個核心角度展開。這組方法是 Java 中實現線程間協作的基礎,其底層依賴于 JVM 對對象鎖的管理機制。

對象監視器(Monitor)

Java 中每個對象都隱式關聯一個對象監視器(Monitor),也稱為 “內置鎖” 或 “管程”。它是實現同步和線程協作的核心數據結構,內部包含三個關鍵部分:

  1. 持有線程:當前獲取到鎖的線程(同一時間只能有一個線程持有)。
  2. 入口集(Entry Set):等待獲取鎖的線程集合(線程狀態為BLOCKED)。
  3. 等待集(Wait Set):調用wait()后釋放鎖并等待被喚醒的線程集合(線程狀態為WAITINGTIMED_WAITING)。

簡單說,Monitor 就像一個 “休息室 + 會議室”:

  • 會議室(鎖)同一時間只能有一個線程使用(持有鎖的線程);
  • 入口集是等待進入會議室的線程隊列;
  • 等待集是在會議室內主動暫停(調用wait())并臨時退出到休息室的線程隊列。
wait()方法的底層執行流程

當線程調用obj.wait()時,底層會執行以下操作(必須在synchronized塊中調用,否則會拋IllegalMonitorStateException):

  1. 釋放當前對象的鎖
    調用wait()的線程必須已經持有obj的鎖(即處于synchronized(obj)塊中)。執行wait()后,線程會主動釋放該鎖,退出 “持有線程” 位置,讓其他線程有機會獲取鎖。

  2. 進入對象的等待集(Wait Set)
    線程釋放鎖后,會從 “運行狀態” 轉入 “等待狀態(WAITING)”,并被放入obj的等待集(休息室)中。此時線程不再參與 CPU 調度,處于阻塞狀態。

  3. 等待被喚醒
    線程在等待集中休眠,直到其他線程調用obj.notify()obj.notifyAll(),才有可能被喚醒。若調用的是wait(long timeout),則超時后也會自動喚醒。

  4. 重新競爭鎖
    被喚醒的線程不會立即執行,而是從等待集轉移到入口集(Entry Set),重新參與鎖的競爭。只有重新獲取到obj的鎖后,才能從wait()方法返回,繼續執行后續代碼。

  • 關鍵細節:被喚醒的線程必須重新競爭鎖,因此wait()通常配合while循環檢查條件(防止虛假喚醒):

    synchronized (obj) {while (條件不滿足) { // 用while而非if,避免虛假喚醒obj.wait();}
    }
    
notify()/notifyAll()的底層執行流程

notify()notifyAll()用于喚醒等待集中的線程,底層流程如下:

  1. notify():從對象的等待集中隨機選擇一個線程,將其從等待集移到入口集(Entry Set),使其有機會重新競爭鎖。
  2. notifyAll():將對象等待集中的所有線程全部移到入口集,讓所有等待線程重新競爭鎖。

注意

  • 調用notify()/notifyAll()的線程不會立即釋放鎖,而是要等當前synchronized塊執行完畢后才釋放。因此,被喚醒的線程需要等待喚醒它的線程釋放鎖后,才能重新競爭鎖。
  • 若等待集中沒有線程,notify()/notifyAll()調用無效果。

3. BLOCKED 狀態的喚醒(如獲取鎖或 I/O 就緒)

  • 獲取鎖的 BLOCKED 線程

    1. 線程因未搶到 synchronized 鎖進入 BLOCKED 狀態,排隊在鎖的入口集(Entry Set)。
    2. 當持有鎖的線程釋放鎖(退出 synchronized 塊),JVM 從入口集中喚醒一個或多個線程(具體策略由 JVM 實現決定)。
    3. 被喚醒的線程競爭鎖,成功后狀態切換為 RUNNABLE。
  • 等待 I/O 的 BLOCKED 線程

    1. 線程發起 I/O 請求后,進入 BLOCKED 狀態(如讀取文件時等待磁盤數據)。
    2. 操作系統負責處理 I/O 操作,完成后向 JVM 發送I/O 完成事件
    3. JVM 接收到事件后,將線程狀態切換為 RUNNABLE,等待 CPU 調度。

四、總結:線程狀態轉換的核心邏輯

線程狀態轉換的本質是JVM 與操作系統協作的資源調度過程

  1. 主動讓出 CPUsleep()wait()等方法讓線程暫時放棄執行權,進入特定狀態。
  2. 阻塞原因解除:超時、被喚醒、資源就緒等條件觸發時,線程重新獲得執行資格。
  3. 競爭 CPU 時間片:所有回到 RUNNABLE 狀態的線程,最終需通過操作系統的 CPU 調度獲得執行機會。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/93825.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/93825.shtml
英文地址,請注明出處:http://en.pswp.cn/web/93825.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

面經整理-猿輔導-內容服務后端-java實習

部門管理系統設計 題目要求 設計部門 MySQL 數據表實現接口:根據中間部門 ID 獲取其下屬葉子部門 ID設計包含子節點列表的 Java 數據對象,并實現批量獲取功能 一、MySQL 部門表設計 表結構 CREATE TABLE department (id BIGINT PRIMARY KEY AUTO_INCREME…

Openharmony之window_manager子系統源碼、需求定制詳解

1. 模塊概述 Window Manager 模塊是 OpenHarmony 操作系統的核心窗口管理系統,負責窗口的創建、銷毀、布局、焦點管理、動畫效果以及與硬件顯示的交互。該模塊采用客戶端-服務端架構,提供完整的窗口生命周期管理和用戶界面交互支持。 1.1架構總覽 Window Manager Client 應…

《CDN加速的安全隱患與解決辦法:如何構建更安全的網絡加速體系》

CDN(內容分發網絡)作為提升網站訪問速度的關鍵技術,被廣泛應用于各類互聯網服務中。然而,在享受加速優勢的同時,CDN也面臨諸多安全隱患。本文將解析常見的CDN安全問題,并提供實用的解決辦法,幫助…

【Linux指南】GCC/G++編譯器:庖丁解牛——從源碼到可執行文件的奇幻之旅

不只是簡單的 gcc hello.c 每一位Linux C/C++開發者敲下的第一行編譯命令,幾乎都是 gcc hello.c -o hello 或 g++ hello.cpp -o hello。這像一句神奇的咒語,將人類可讀的源代碼變成了機器可執行的二進制文件。但在這條簡單的命令背后,隱藏著一個如同精密鐘表般復雜的多步流…

地區電影市場分析:用Python爬蟲抓取貓眼_燈塔專業版各地區票房

在當今高度數據驅動的影視行業,精準把握地區票房表現是制片方、宣發團隊和影院經理做出關鍵決策的基礎。一部電影在北上廣深的表現與二三線城市有何差異?哪種類型的電影在特定區域更受歡迎?回答這些問題,不能再依賴“拍腦袋”和經…

Spark03-RDD02-常用的Action算子

一、常用的Action算子 1-1、countByKey算子 作用:統計key出現的次數,一般適用于K-V型的RDD。 【注意】: 1、collect()是RDD的算子,此時的Action算子,沒有生成新的RDD,所以,沒有collect()&…

[Android] 顯示的內容被導航欄這擋住

上圖中彈出的對話框的按鈕“Cancel/Save”被導航欄遮擋了部分顯示&#xff0c;影響了使用。Root cause: Android 應用的主題是 Theme.AppCompat.Light1. 修改 AndroidManifest.xml 將 application 標簽的 android:theme 屬性指向新的自定義主題&#xff1a;<applicationandr…

分貝單位全指南:從 dB 到 dBm、dBc

引言在射頻、音頻和通信工程中&#xff0c;我們經常會在示波器、頻譜儀或測試報告里看到各種各樣的dB單位&#xff0c;比如 dBm、dBc、dBV、dBFS 等。它們看起來都帶個 dB&#xff0c;實則各有不同的定義和參考基準&#xff1a;有的表示相對功率&#xff0c;有的表示電壓電平&a…

怎么確定mysql 鏈接成功了呢?

asyncio.run(test_connection()) ? Connection failed: cryptography package is required for sha256_password or caching_sha2_password auth methods 根據你提供的錯誤信息,問題出現在 MySQL 的認證插件和加密連接配置上。以下是幾種解決方法: 1. 安裝 cryptography 包…

(5)軟件包管理器 yum | Vim 編輯器 | Vim 文本批量化操作 | 配置 Vim

Ⅰ . Linux 軟件包管理器 yum01 安裝軟件在 Linux 下安裝軟件并不像 Windows 下那么方便&#xff0c;最通常的方式是去下載程序的源代碼并進行編譯&#xff0c;從而得到可執行程序。正是因為太麻煩&#xff0c;所以有些人就把一些常用的軟件提前編譯好并做成軟件包&#xff0c;…

VGG改進(3):基于Cross Attention的VGG16增強方案

第一部分&#xff1a;交叉注意力機制解析1.1 注意力機制基礎注意力機制的核心思想是模擬人類的選擇性注意力——在處理信息時&#xff0c;對重要部分分配更多"注意力"。在神經網絡中&#xff0c;這意味著模型可以學習動態地加權輸入的不同部分。傳統的自注意力(Self-…

代理ip平臺哪家好?專業代理IP服務商測評排行推薦

隨著互聯網的深度發展&#xff0c;通過網絡來獲取全球化的信息資源&#xff0c;已成為企業與機構在競爭中保持優勢的一大舉措。但想要獲取其他地區的信息&#xff0c;可能需要我們通過代理IP來實現。代理IP平臺哪家好&#xff1f;下文就讓我們從IP池資源與技術優勢等細節&#…

PWA》》以京東為例安裝到PC端

如果訪問 瀏覽器右側出現 安裝 或 點擊這個 也可以完成安裝桌面 會出現 如下圖標

Linux系統:C語言進程間通信信號(Signal)

1. 引言&#xff1a;從"中斷"到"信號"想象一下&#xff0c;你正在書房專心致志地寫代碼&#xff0c;這時廚房的水燒開了&#xff0c;鳴笛聲大作。你會怎么做&#xff1f;你會暫停&#xff08;Interrupt&#xff09; 手頭的工作&#xff0c;跑去廚房關掉燒水…

LoRa 網關組網方案(二)

LoRa 網關組網方案 現有需求&#xff1a;網關每6秒接收不同節點的數據&#xff0c;使用SX1262芯片。 以下是完整的組網方案&#xff1a;1. 網絡架構設計 采用星型拓撲&#xff1a; 網關&#xff1a;作為中心節點&#xff0c;持續監聽多個信道節點&#xff1a;分布在網關周圍&am…

服裝外貿系統軟件怎么用才高效防風險?

服裝外貿系統軟件概述 服裝外貿系統軟件&#xff0c;如“艾格文ERP”&#xff0c;是現代外貿企業不可或缺的管理工具。它整合了訂單處理、庫存管理、客戶資源保護、財務控制等多功能模塊&#xff0c;旨在全面提升業務運營效率。通過系統化的管理方式&#xff0c;艾格文ERP能夠從…

【沉浸式解決問題】peewee.ImproperlyConfigured: MySQL driver not installed!

目錄一、問題描述二、原因分析三、解決方案? 推薦&#xff1a;安裝 pymysql&#xff08;純 Python&#xff0c;跨平臺&#xff0c;安裝簡單&#xff09;? 可選&#xff1a;安裝 mysqlclient&#xff08;更快&#xff0c;但需要本地編譯環境&#xff09;? 總結四、mysql-conn…

C++進階-----C++11

作者前言 &#x1f382; ??????&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ?&#x1f382; 作者介紹&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

(論文速讀)航空軸承剩余壽命預測:多生成器GAN與CBAM融合的創新方法

論文題目&#xff1a;Remaining Useful Life Prediction Approach for Aviation Bearings Based on Multigenerator Generative Adversarial Network and CBAM&#xff08;基于多發生器生成對抗網絡和CBAM的航空軸承剩余使用壽命預測方法&#xff09;期刊&#xff1a;IEEE TRAN…

3ds Max 流體模擬終極指南:從創建到渲染,打造真實液體效果

流體模擬是提升 3D 場景真實感的重要技術之一。無論是模擬飛瀑流泉、杯中溢出的飲料&#xff0c;還是黏稠的蜂蜜或熔巖&#xff0c;熟練掌握流體動力學無疑能為你的作品增色不少。本文將以 3ds Max 為例&#xff0c;系統講解流體模擬的創建流程與渲染方法&#xff0c;幫助你實現…