Java - AbstractQueuedSynchronizer

AQS簡介

AQS全稱AbstractQueuedSynchronizer,抽象隊列同步器,是一個實現同步組件的基礎框架。AQS使用一個int類型的成員變量state維護同步狀態,通過內置的同步隊列(CLH鎖、FIFO)完成線程的排隊工作,底層主要是通過CAS操作和volatile特性實現。

它主要包含兩種模式:獨占模式(例如ReentrantLock)和共享模式(例如CountDownLatch)。關鍵方法包括acquire和release,用于獨占模式下的獲取和釋放操作,以及acquireShared和releaseShared,用于共享模式下的操作。

它簡化了同步組件的實現方式,屏蔽了同步狀態的管理、線程的排隊等待與喚醒等底層操作。我們只需要通過繼承實現AQS中的抽象方法,即可實現不同同步語義的同步組件。例如ReentrantLock這種獨占式同步組件,核心邏輯僅重寫了tryAcquire和tryRelease等少數方法,就實現了可重入獨占式鎖的功能。

AQS通過繼承來擴展其功能,子類通過繼承AQS實現抽象方法來管理同步狀態,同步組件則通過聚合子類的方法來實現自己的同步特性,獨占式或共享式。

使用AQS實現一個自定義排他鎖

繼承AQS:
創建一個新的類,繼承AbstractQueuedSynchronizer。

實現核心方法:
實現tryAcquire和tryRelease方法(用于獨占模式),或實現tryAcquireShared和tryReleaseShared方法(用于共享模式)。

內部類Sync:
通常創建一個內部靜態類Sync,擴展AQS并實現上述方法。

對外方法:
在外部類中,提供獲取和釋放的方法,內部調用AQS的方法acquire、release、acquireShared和releaseShared。

import java.util.concurrent.locks.AbstractQueuedSynchronizer;public class SimpleLock {private final Sync sync = new Sync();private static class Sync extends AbstractQueuedSynchronizer {@Overrideprotected boolean tryAcquire(int arg) {if (compareAndSetState(0, 1)) {setExclusiveOwnerThread(Thread.currentThread());return true;}return false;}@Overrideprotected boolean tryRelease(int arg) {if (getState() == 0) throw new IllegalMonitorStateException();setExclusiveOwnerThread(null);setState(0);return true;}@Overrideprotected boolean isHeldExclusively() {return getExclusiveOwnerThread() == Thread.currentThread();}}public void lock() {sync.acquire(1);}public void unlock() {sync.release(1);}public boolean isLocked() {return sync.isHeldExclusively();}
}

使用AQS實現一個自定義共享鎖

import java.util.concurrent.locks.AbstractQueuedSynchronizer;public class SimpleSemaphore {private final Sync sync;public SimpleSemaphore(int permits) {sync = new Sync(permits);}private static class Sync extends AbstractQueuedSynchronizer {Sync(int permits) {setState(permits);}@Overrideprotected int tryAcquireShared(int acquires) {for (;;) {int available = getState();int remaining = available - acquires;if (remaining < 0 || compareAndSetState(available, remaining)) {return remaining;}}}@Overrideprotected boolean tryReleaseShared(int releases) {for (;;) {int current = getState();int next = current + releases;if (compareAndSetState(current, next)) {return true;}}}}public void acquire() throws InterruptedException {sync.acquireSharedInterruptibly(1);}public void release() {sync.releaseShared(1);}
}

同步隊列和條件隊列的區別


同步隊列(synchronization queue)和條件隊列(condition queue)是AbstractQueuedSynchronizer(AQS)中的兩個不同的隊列,它們有不同的用途和工作機制。

同步隊列

  • 用途:管理所有等待獲取鎖或同步狀態的線程。
  • 觸發條件:當線程嘗試獲取鎖或同步狀態失敗時進入隊列。
  • 結構:雙向鏈表。
  • 作用:維護線程的順序,確保公平競爭。
  • 喚醒機制:當鎖釋放或同步狀態改變時,喚醒隊列中的下一個線程。

條件隊列

  • 用途:管理等待特定條件的線程(通過ConditionObject)。
  • 觸發條件:當線程調用await()方法時進入隊列,并釋放當前持有的鎖。
  • 結構:單向鏈表。
  • 作用:等待特定條件的滿足,如某個狀態的變化。
  • 喚醒機制:當條件滿足時(通過signal()或signalAll()),線程從條件隊列移動到同步隊列,等待重新獲取鎖。

為什么await方法一定要加鎖才能調用

我理解條件隊列現在的實現是在await方法先完全釋放鎖,再進入休眠狀態等待喚醒,被喚醒后重新嘗試加鎖。先完全釋放鎖,是為了防止當前線程持有鎖時錯誤休眠,若當前線程持有鎖進入休眠狀態,即使當前線程被喚醒,也是嘗試加鎖而不是解鎖,那么其他線程永遠無法拿到鎖。因此先完全解鎖再休眠,被喚醒后重新嘗試加鎖,應該是出于防止鎖饑餓與死鎖的考慮。

AQS獨占式加鎖(以ReentrantLock加鎖為例)

加鎖流程

加鎖源碼分析

解鎖流程

解鎖源碼分析

CLH鎖(同步隊列的原型)

CLH鎖是對自旋鎖的一種改良,自旋鎖只適合競爭不激烈,加鎖時間短的場景,原因是自旋鎖有2個問題,第一,存在鎖饑餓問題,可能會出現某個線程一直拿不到鎖的情況;第二,鎖狀態中心化,激烈競爭時會導致CPU的高速緩存頻繁失效,導致性能降低。

CLH隊列鎖有效地解決了以上2個問題,首先,CLH鎖通過增加隊列進行排隊,確保所有線程都有機會拿到鎖;第二,CLH鎖的每個線程監視的都是上一個節點的鎖狀態,因此鎖狀態是去中心化的,不會導致CPU高速緩存頻繁失效。

CLH鎖實現源碼

import java.util.concurrent.atomic.AtomicReference;public class CLH {private final ThreadLocal<Node> node = ThreadLocal.withInitial(Node::new);private final AtomicReference<Node> tail = new AtomicReference<>(new Node());private static class Node {// ①鎖定狀態必須用volatile修飾以確保內存可見性private volatile boolean locked;}public void lock() {Node node = this.node.get();node.locked = true;Node pre = this.tail.getAndSet(node);while (pre.locked) ;}public void unlock() {Node node = this.node.get();node.locked = false;// ②重置當前線程對應的Node節點避免死鎖this.node.set(new Node());}
}

原理分析

觀察代碼可以發現,CLH沒有前驅或后繼指針,因為CLH鎖是一種隱式隊列,入隊只需要添加新的tail節點,出隊只需要修改頭部狀態。注釋①處必須用volatile修飾,以確保內存可見性與代碼有序性。注釋②處必須重置線程Node,否則當一個線程重復加鎖時,就有可能死鎖,死鎖原因可以看這篇文章的解鎖分析部分。

CLH鎖的優點是性能優異、實現簡單、加鎖公平、擴展性強。但缺點是有自旋操作,長時間加鎖會浪費CPU性能,再就是功能單一,不支持復雜的功能。

針對以上兩個缺點,AQS都做了改進。針對第一個缺點,將自旋改為了線程阻塞等待;針對第二個缺點,AQS做了很多改造和擴展,例如增加了每個節點的狀態waitStatus、顯式維護了前驅和后繼節點等等,基于這些擴展,AQS實現了獨占鎖、共享鎖、線程排隊、狀態傳播等復雜功能。

參考鏈接

從ReentrantLock的實現看AQS的原理及應用 - 美團技術團隊

AQS 詳解 | JavaGuide

AQS的前菜—詳解CLH隊列鎖_clh鎖-CSDN博客

Java AQS 核心數據結構-CLH 鎖

JUC鎖:核心類AQS源碼詳解 - 拿了桔子跑-范德依彪 - 博客園

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

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

相關文章

echarts 散點圖修改散點圖中圖形形狀顏色大小

話不多說&#xff0c;直接上代碼 let option {color:[xxx, xxx, xxx, xxx], //直接設置color可修改圖形顏色title: {text: 散點圖圖形,},tooltip: {trigger: axis,axisPointer: {type: cross}},legend: {top: 2,right:2,itemWidth: 10,itemHeight: 10,textStyle:{fontSize:14}…

shell腳本條件語句和循環語句

文章目錄 一、條件語句測試比較整數數值字符串比較邏輯運算雙中括號&#xff08; &#xff09;{ }if語句結構case語句 二、循環語句基礎知識for循環whileuntil雙重循環及跳出循環 一、條件語句 測試 條件測試&#xff1a;判斷某需求是否滿足&#xff0c;需要由測試機制來實現…

視頻分類——C3D使用

整體比較分散&#xff0c;可能很多源碼都需要修改&#xff0c;需要有耐心。 一、數據準備 PS 調研后&#xff0c;上手容易代碼比較簡潔的是&#xff1a;https://github.com/Niki173/C3D/tree/main 因為源碼很多參數都寫死到了源碼中&#xff0c;沒有解耦&#xff0c;并且默…

CCF-CSP認證 2024年3月 4.化學方程式配平

題解&#xff1a;首先完成數據的讀入&#xff0c;然后高斯消元求秩按題意解即可 #pragma GCC optimize(2, 3, "Ofast", "inline") #include <bits/stdc.h> using namespace std; const int maxn 100;using matrix double[maxn][maxn]; using vect…

5.20Git

版本控制工具Git&#xff0c;其他的工具還有SVN 共享代碼&#xff0c;追溯記錄&#xff0c;存儲.c文件 Git實現的功能&#xff1a;回溯&#xff08;以前某個時間節點的數據情況&#xff09;共享&#xff08;大家共享修改&#xff09; Git&#xff1a;80% SVN&#xff…

QT tableWidget詳細分析

一.定義 QTableWidget是一個用于顯示表格數據的Qt控件&#xff0c;它是一個基于Qt Model/View框架的視圖組件。QTableWidget提供了一種簡單的方式來展示和編輯表格數據&#xff0c;用戶可以通過添加行、列和單元格來構建一個完整的數據表格。 下面是一些QTableWidget的主要特點…

The Missing Semester of Your CS Education(計算機教育中缺失的一課)

Shell 工具和腳本(Shell Tools and Scripting) 一、shell腳本 1.1、變量賦值 在bash中為變量賦值的語法是foobar&#xff0c;訪問變量中存儲的數值&#xff0c;其語法為 $foo。 需要注意的是&#xff0c;foo bar &#xff08;使用空格隔開&#xff09;是不能正確工作的&…

網工內推 | 香港移動,10年以上數通經驗,CCIE,5W-6W

01 香港移動招聘 &#x1f537;招聘崗位&#xff1a;網絡工程師 &#x1f537;崗位要求&#xff1a; 需要有10年及以上數通經驗&#xff0c;有CCIE 證書&#xff0c;懂技術管理&#xff0c;溝通暢通 &#x1f537;語言要求&#xff1a; 粵語英語 &#x1f537;薪資&#xff1…

基于灰狼優化算法優化RBF(GWO-RBF)的數據回歸預測(多輸入多輸出)

代碼原理及流程 基于灰狼優化算法優化多輸入多輸出&#xff08;MIMO&#xff09;的RBF神經網絡的數據回歸預測&#xff0c;可以采取以下步驟&#xff1a; 1. 數據準備&#xff1a;準備包含多個輸入特征和多個輸出目標的數據集&#xff0c;確保數據已經經過預處理和歸一化。 …

TCP - 半連接隊列和全連接隊列

目錄 一、半連接隊列和全連接隊列的概念 二、全連接隊列溢出 三、半連接隊列溢出 一、半連接隊列和全連接隊列的概念 1. 半連接隊列&#xff1a;服務端收到客戶端發送的 SYN 包時&#xff0c;內核會將該連接加入半連接 SYN 隊列&#xff0c;并向客戶端返回響應 2. 全連接隊…

CSS基礎(第二天)

Emmet語法 快速生成HTML結構語法 1. 生成標簽 直接輸入標簽名 按tab鍵即可 比如 div 然后tab 鍵&#xff0c; 就可以生成 <div></div> 2. 如果想要生成多個相同標簽 加上 * 就可以了 比如 div*3 就可以快速生成3個div 3. 如果有父子級關系的標簽&#xff0c;可以…

算法刷題筆記 數的范圍(C++實現)(二分法重要例題)

文章目錄 題目描述題目思路題目代碼&#xff08;C&#xff09;題目感想 題目描述 給定一個按照升序排列的長度為n的整數數組&#xff0c;以及q個查詢。對于每個查詢&#xff0c;返回一個元素k的起始位置和終止位置&#xff08;位置從0開始計數&#xff09;。如果數組中不存在該…

Docker【2】iptables 錯誤解決

iptables 錯誤解決 問題說明問題分析解決步驟1. 確保 iptables 模塊已加載2. 檢查和重啟 docker 服務3. 檢查 firewalld 狀態4. 重置 iptables 規則5. 查看和更新 Docker 配置 總結 問題說明 執行的 docker 命令如下&#xff0c;啟動 nginx 并設置宿主機端口 (8080) 與容器端口…

學習Uni-app開發小程序Day25

這一章學習了觸底加載更多阻止無效的網絡請求、分類列表存入Storage在預覽頁面讀取緩存展示、通過swiper的事件實現真正的壁紙預覽及切換 觸底加載更多阻止無效的網絡請求、load-more樣式的展現 前面已經學習了當列表觸底后&#xff0c;會繼續加載&#xff0c;當到最后一層后…

自動化測試--利用pytest實現整條業務鏈路測試

? 概述 前面一章講解了單個接口的測試&#xff0c;但是實際項目中&#xff0c;因為權限和登錄狀態的限制&#xff0c;大部分接口沒辦法直接訪問到&#xff0c;這時候我們想訪問到一個系統的接口&#xff0c;就需要模擬用戶登錄拿到用戶的token和所擁有的權限之后再將這些信息…

vivado2020.2創建hls仿真工程實現led閃爍

下載vivado2020.2后會有這個出現在桌面 點擊進入創建工程&#xff0c;這里注意不要有前面的\我再復制的時候復制錯了導致創建失敗 按f光標就會跳轉到下一個f開頭的函數處&#xff0c;要查找其他函數也同理 生成了一個synthesis summary文件 找到目錄下生成的.v文件 an 點…

Pod進階——資源限制以及探針檢查

目錄 一、資源限制 1、資源限制定義&#xff1a; 2、資源限制request和limit資源約束 3、Pod和容器的資源請求和限制 4、官方文檔示例 5、CPU資源單位 6、內存資源單位 7、資源限制實例 ①編寫yaml資源配置清單 ②釋放內存&#xff08;node節點&#xff0c;以node01為…

【知識蒸餾】多任務模型 logit-based 知識蒸餾實戰

一、什么是邏輯&#xff08;logit&#xff09;知識蒸餾 Feature-based蒸餾原理是知識蒸餾中的一種重要方法&#xff0c;其關鍵在于利用教師模型的隱藏層特征來指導學生模型的學習過程。這種蒸餾方式旨在使學生模型能夠學習到教師模型在特征提取和表示方面的能力&#xff0c;從…

有些錯誤,常犯常新、常新常犯:記錄一個使用element-plus的tooltip組件的錯誤

使用element-plus的tooltip組件&#xff0c;最開始的寫法是這樣的&#xff1a; <el-tooltipclass"box-item"effect"dark"content"tooltip content" ><el-button v-if"isDisabled" :underline"false" type"pr…

持續總結中!2024年面試必問 20 道 Redis面試題(五)

上一篇地址&#xff1a;持續總結中&#xff01;2024年面試必問 20 道 Redis面試題&#xff08;四&#xff09;-CSDN博客 九、Redis的同步機制了解么&#xff1f; Redis 的同步機制是其復制策略的核心部分&#xff0c;確保數據在主節點&#xff08;master&#xff09;和從節點…