LockSupport與Condition解析

本章我們介紹兩個Java 并發包中用于線程協作的工具--LockSupport和Condition

LockSupport:

Java 并發包(java.util.concurrent.locks)提供了基于許可(permit)的線程阻塞和喚醒機制--LockSupport

對于LockSupport是通過方法park以及unpark來對線程進行阻塞和喚醒的

    public static void park() {UNSAFE.park(false, 0L);}public static void unpark(Thread var0) {if (var0 != null) {UNSAFE.unpark(var0);}}

我們可以看出park方法很簡單只是調用了Unsafe?的方法park。Unsafe?正如它名字而言是 Java 中一個?高度危險且未被官方正式支持?的類,位于?sun.misc?包下(JDK 9 后移至?jdk.internal.misc?包)。它提供了一系列?直接操作底層資源?的方法,允許開發者繞過 Java 語言的安全機制,直接訪問內存、操作線程狀態等。所以LockSupport就是基于unsafe類進行包裝后的類,將原來的不安全類封裝成了一個安全類供開發者使用。對于park方法的兩個參數一個是Boolean類型一個是long類型,分別用來表示是否為絕對時間以及阻塞的時長,對于0L則是永久阻塞。

對于unpark方法來說則是多了一個參數Thread,這個參數的作用是用來指定喚醒的線程。為什么park不需要參數而unpark需要參數呢,因為unpark喚醒的都是其他線程,當本線程進入阻塞后則無法自己喚醒自己只能通過其他線程來喚醒自己。

Condition:

Condition?是 Java 并發包(java.util.concurrent.locks)中的一個接口,用于替代傳統的?Object.wait()Object.notify()?和?Object.notifyAll(),提供更靈活、更強大的線程間協作機制。它通常與?Lock?接口配合使用,實現精細化的線程等待和喚醒操作。

也就是說Condition的定位其實與Object.wait類似,都是協助鎖來實現線程的協作機制。

特性ConditionObject.wait()/notify()
鎖機制必須與?Lock?顯式關聯(如?ReentrantLock)。必須在?synchronized?塊中調用。
等待隊列每個?Condition?獨立維護一個等待隊列,可創建多個條件隊列(如?notFullnotEmpty)。每個對象只有一個等待隊列,所有線程共享。
喚醒方式signal():喚醒一個等待線程;
signalAll():喚醒所有等待線程。
notify():隨機喚醒一個線程;
notifyAll():喚醒所有線程。
中斷支持await()?可響應中斷(拋出?InterruptedException),也支持不可中斷模式(awaitUninterruptibly())。wait()?只能響應中斷(拋出異常),無法禁用。
超時機制支持靈活的超時等待(如?await(long, TimeUnit))。僅支持?wait(long timeout)(毫秒級)。

其中Condition接口的實現類則是在AQS內部中,而AQS則賦予了Condition靈魂,下面我們來看看Condition子類ConditionObject的源碼。

在ConditionObject中我們從Condition最核心的兩個方法await方法和signal方法來說起

public final void await() throws InterruptedException {if (Thread.interrupted()) {throw new InterruptedException();} else {Node var1 = this.addConditionWaiter();long var2 = AbstractQueuedLongSynchronizer.this.fullyRelease(var1);int var4 = 0;while(!AbstractQueuedLongSynchronizer.this.isOnSyncQueue(var1)) {LockSupport.park(this);if ((var4 = this.checkInterruptWhileWaiting(var1)) != 0) {break;}}if (AbstractQueuedLongSynchronizer.this.acquireQueued(var1, var2) && var4 != -1) {var4 = 1;}if (var1.nextWaiter != null) {this.unlinkCancelledWaiters();}if (var4 != 0) {this.reportInterruptAfterWait(var4);}}
}

首先則是線程中斷位的判斷如果已經中斷則直接拋出異常(由此可以看出await方法是可中斷的方法)。隨后則是調用了addConditionWaiter方法,這個方法的作用就是將當前線程加入到Condition所維持的隊列中,在我們解析addConditionWaiter方法之前先看一下Condition的屬性

    public class ConditionObject implements Condition, Serializable {private static final long serialVersionUID = 1173984872572414699L;private transient Node firstWaiter;private transient Node lastWaiter;private static final int REINTERRUPT = 1;private static final int THROW_IE = -1;。。。。}

可以看出含有兩個屬性firstWaiter和lastWaiter,這兩個屬性分別表示的是Condition所維持的鏈表的表頭和表尾,由此我們又可以看出ConditionObject 則是用一個鏈表來串聯起整個隊列的。

然后我們開始進入addConditionWaiter方法中來看看是如何加入隊列的

        private Node addConditionWaiter() {Node var1 = this.lastWaiter;if (var1 != null && var1.waitStatus != -2) {this.unlinkCancelledWaiters();var1 = this.lastWaiter;}Node var2 = new Node(Thread.currentThread(), -2);if (var1 == null) {this.firstWaiter = var2;} else {var1.nextWaiter = var2;}this.lastWaiter = var2;return var2;}

代碼可以看出首先將隊尾的Node節點取出并且檢查狀態,如果狀態不符合要求則會清除出隊列。

之后開始初始化本線程的Node節點,并且放在隊尾后面。好了這個方法的大致功能已經捋順接下來我們看看下面的方法

                long var2 = AbstractQueuedLongSynchronizer.this.fullyRelease(var1);int var4 = 0;while(!AbstractQueuedLongSynchronizer.this.isOnSyncQueue(var1)) {LockSupport.park(this);if ((var4 = this.checkInterruptWhileWaiting(var1)) != 0) {break;}}if (AbstractQueuedLongSynchronizer.this.acquireQueued(var1, var2) && var4 != -1) {var4 = 1;}if (var1.nextWaiter != null) {this.unlinkCancelledWaiters();}if (var4 != 0) {this.reportInterruptAfterWait(var4);}

隨后就會調用AQS的方法進行鎖釋放(由于線程已經進入Condition隊列中),隨后則會一個while循環調用isOnSyncQueue進行校驗保證當前Node節點不會在AQS的同步隊列,這時候就會有疑惑了為什么要保證不會在AQS的同步隊列呢,原因就是當Condition調用signal方法的時候被喚醒的線程會從Condition隊列中移除轉而放入到AQS維護的CLH同步隊列中去。所以這里的循環查看是否在同步隊列換個意思就是保證當前Node節點沒有被喚醒。

在保證當前沒有被喚醒之后則會調用?LockSupport.park(this)來講當前的線程阻塞。由此可見LockSupport很純粹也很底層,目的就是為了將當前線程進行阻塞或者喚醒。在進入阻塞之后后續的代碼則不會執行而是等到喚醒之后才會執行。

喚醒之后首先查看當前線程的中斷位,如果被中斷則直接跳出循環。

隨后則參與鎖的競爭調用了acquireQueued方法表示來占有鎖,占有鎖成功之后則會執行后續的方法如果后面還有節點那么會遍歷清除后面的節點。

最后進行判斷如果中斷位是否開啟并且進行處理中斷位

下面舉一個常用示例

// 示例:生產者-消費者模型
lock.lock();
try {while (queue.isFull()) {notFull.await(); // 等待隊列不滿}// await() 返回后,線程已持有鎖,繼續執行queue.add(item); // 生產元素notEmpty.signal(); // 通知消費者
} finally {lock.unlock();
}

整體流程:

  1. 開始?→?檢查線程中斷(若已中斷,拋異常)
  2. 創建節點加入 Condition 隊列?→?釋放鎖
  3. 循環檢查節點是否在同步隊列
    • ?→ 調用park()阻塞 → 等待喚醒 / 中斷
    • ?→ 跳出循環
  4. 重新競爭鎖acquireQueued)→?獲取鎖后處理中斷標記
  5. 清理 Condition 隊列無效節點?→?根據中斷狀態處理異常或恢復標志
  6. 方法返回,線程持有鎖繼續執行后續邏輯

下一章節我們將把最后的signal函數源碼解析給講述完畢

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

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

相關文章

【機器學習基礎】機器學習入門核心算法:邏輯回歸(Decision Tree)

機器學習入門核心算法:邏輯回歸(Decision Tree) 一、算法邏輯1.1 基本概念1.2 算法流程 二、算法原理與數學推導2.1 特征選擇指標信息熵(ID3算法)信息增益(Information Gain)信息增益率&#xf…

網絡編程3

管道的性質 讀緩沖區為空,read阻塞寫緩沖區為空,write阻塞一端先close,另一端繼續read,read不阻塞,立刻返回0一端先close,另一端繼續write,write會觸發SIGPIPE信號,進程異常終止 soc…

influxdb時序數據庫

以下概念及操作均來自influxdb2 官方文檔 InfluxDB2 is the platform purpose-built to collect, store, process and visualize time series data. Time series data is a sequence of data points indexed in time order. Data points typically consist of successive meas…

洛谷 P3372 【模板】線段樹 1

【題目鏈接】 洛谷 P3372 【模板】線段樹 1 【題目考點】 1. 線段樹 2. 樹狀數組 【解題思路】 本題要求維護區間和,實現區間修改、區間查詢。 可以使用樹狀數組或線段樹完成該問題,本文僅介紹使用線段樹的解法。 解法1:線段樹 線段樹…

軟件更新 | TSMaster 202504 版本已上線!三大功能讓車載測試更智能

車載測試的智能化時代正在加速到來!TSMaster 202504 版本正式發布,本次更新聚焦以太網通信與數據高效處理,帶來三大核心功能升級—以太網報文信息過濾、XCP on Ethernet支持、按時間范圍離線回放,助力工程師更精準、更靈活地完成測…

java-單列集合list與set。

集合定位:存儲數據的容器 與數組的區別: 數組只能存儲同種數據類型數據,集合可以存儲不同類型的數據。 數組的長度一旦創建長度不可變,集合的長度是可變的 數組的操作單一,集合的操作比較豐富(增刪改查&…

ai之pdf解析工具 PPStructure 還是PaddleOCR

目錄 重點是四 先用 PPStructure 版面分析,分成不同的塊兒,再選用 PaddleOCR、或PPStructure基礎路徑OCR模型配置OCR模型配置GPU配置硬件配置性能配置一、框架選型對比分析1. **PaddleOCR核心能力**2. **PP-Structure核心能力**3. **選型結論**二、錯誤根因分析與修復方案1. …

Android計算機網絡學習總結

TCP vs UDP 核心區別?? ?題目?:TCP為什么稱為可靠傳輸協議?UDP在哪些場景下比TCP更具優勢? ?得分要點?: ?可靠性機制? 三握四揮建立可靠連接確認應答(ACK) 超時重傳滑動窗口流量控制擁塞控制&…

深入解析Java組合模式:構建靈活樹形結構的藝術

引言:當對象需要樹形組織時 在日常開發中,我們經常需要處理具有層次結構的對象集合。比如: 文件系統中的文件夾與文件GUI界面中的容器與控件企業組織架構中的部門與員工 這類場景中的對象呈現明顯的整體-部分層次結構,如何優雅…

mobaxterm通過ssh登錄docker無圖形界面

1. 流程 下面是使用Mobaxterm通過SSH登錄Docker無圖形界面的步驟: 步驟 操作 1 在本地安裝Mobaxterm 2 配置Mobaxterm連接SSH 3 啟動Docker容器 4 在Mobaxterm中通過SSH連接到Docker容器 2. 操作步驟 步驟1:安裝Mobaxterm 首先&#xff…

【趙渝強老師】HBase的體系架構

HBase是大表(BigTable)思想的一個具體實現。它是一個列式存儲的NoSQL數據庫,適合執行數據的分析和處理。簡單來說,就是適合執行查詢操作。從體系架構的角度看,HBase是一種主從架構,包含:HBase H…

linux 新增驅動宏config.in配置

?1. 添加配置宏步驟? ?1.1 修改 Kconfig(推薦方式)? ?定位 Kconfig 文件? 內核各子目錄(如 drivers/char/)通常包含 Kconfig 文件,用于定義模塊配置選項7。?添加宏定義? 示例:在 drivers/char/Kc…

關于git的使用

下載git 可以去git的官網下載https://git-scm.com/downloads 也可以去找第三方的資源下載,下載后是一個exe應用程序,直接點開一直下一步就可以安裝了 右鍵任意位置顯示這兩個就代表成功,第一個是git官方的圖形化界面,第二個是用…

WPF【11_8】WPF實戰-重構與美化(UI 與視圖模型的聯動,實現INotifyPropertyChanged)

11-13 【重構】INotifyPropertyChanged 與 ObservableCollection 現在我們來完成新建客戶的功能。 當用戶點擊“客戶添加”按鈕以后系統會清空當前所選定的客戶,客戶的詳細信息以及客戶的預約記錄會從 UI 中被清除。然后我們就可以在輸入框中輸入新的客戶信息了&am…

ArkUI:鴻蒙應用響應式與組件化開發指南(一)

文章目錄 引言1.ArkUI核心能力概覽1.1狀態驅動視圖1.2組件化:構建可復用UI 2.狀態管理:從單一組件到全局共享2.1 狀態裝飾器2.2 狀態傳遞模式對比 引言 鴻蒙生態正催生應用開發的新范式。作為面向全場景的分布式操作系統,鴻蒙的北向應用開發…

List優雅分組

一、前言 最近小永哥發現,在開發過程中,經常會遇到需要對list進行分組,就是假如有一個RecordTest對象集合,RecordTest對象都有一個type的屬性,需要將這個集合按type屬性進行分組,轉換為一個以type為key&…

AI與.NET技術實操系列(八):使用Catalyst進行自然語言處理

引言 自然語言處理(Natural Language Processing, NLP)是人工智能領域中最具活力和潛力的分支之一。從智能客服到機器翻譯,再到語音識別,NLP技術正以其強大的功能改變著我們的生活方式和工作模式。 Catalyst的推出極大降低了NLP…

MySQL 8.0 OCP 1Z0-908 題目解析(13)

題目49 Choose the best answer. t is a non - empty InnoDB table. Examine these statements, which are executed in one session: BEGIN; SELECT * FROM t FOR UPDATE;Which is true? ○ A) mysqlcheck --analyze --all - databases will execute normally on all ta…

Docker 一鍵部署倒計時頁面:Easy Countdown全設備通用

Easy Countdown 介紹 Easy countdown是一個易于設置的倒計時頁面。可以設置為倒計時或計時器。可用于個人生活、工作管理、教育、活動策劃等多個領域。 🚢 項目地址 Github:https://github.com/Yooooomi/easy-countdown 🚀Easy Countdown …

Python訓練打卡Day35

模型可視化與推理 知識點回顧: 三種不同的模型可視化方法:推薦torchinfo打印summary權重分布可視化進度條功能:手動和自動寫法,讓打印結果更加美觀推理的寫法:評估模式 模型結構可視化 理解一個深度學習網絡最重要的2點…