引言:AQS在Java并發體系中的核心地位
AQS(AbstractQueuedSynchronizer)作為Java并發包的底層基石,是理解ReentrantLock、Semaphore等同步工具的關鍵。
在Java架構師面試中,AQS的原理與應用是高頻考點,掌握其核心機制對理解JUC包和構建高并發系統至關重要。
本文將從原理、應用、源碼到Spring生態實踐進行全面解析,幫助讀者系統掌握這一核心技術。
一、AQS核心原理深度剖析
1.1 AQS的架構設計與核心組件
AQS是Java并發包中用于構建鎖和同步器的抽象框架,其設計包含三大核心組件:
1.1.1 三大核心組件詳解
組件名稱 | 技術實現 | 核心作用 |
---|---|---|
狀態變量state | volatile int,通過CAS操作更新 | 存儲同步狀態,不同場景含義不同(如鎖重入次數、信號量許可數等) |
CLH等待隊列 | 雙向鏈表,由Node節點組成 | 管理等待線程的FIFO順序,實現線程阻塞與喚醒機制 |
模板方法 | 抽象方法需子類實現 | 定義同步邏輯接口(如tryAcquire、tryRelease等),實現模板方法模式 |
1.1.2 Node節點核心字段解析
static final class Node {// 節點狀態:CANCELLED(1)、SIGNAL(-1)、CONDITION(-2)、PROPAGATE(-3)volatile int waitStatus;// 前驅節點引用volatile Node prev;// 后繼節點引用volatile Node next;// 關聯的線程volatile Thread thread;// 條件隊列中的后繼節點Node nextWaiter;
}
1.1.3 CLH隊列結構示意圖
CLH隊列關鍵特性說明
- 雙向鏈表結構:
- 每個節點包含
prev
和next
指針 - 頭節點(Head)的prev為null
- 尾節點(Tail)的next為null
- 每個節點包含
- 節點內部結構:
static final class Node {volatile int waitStatus; // 等待狀態volatile Node prev; // 前驅節點volatile Node next; // 后繼節點volatile Thread thread; // 關聯線程Node nextWaiter; // 條件隊列鏈接 }
- 等待狀態(waitStatus):
SIGNAL(-1)
:后繼節點需要喚醒CANCELLED(1)
:線程已取消CONDITION(-2)
:在條件隊列中0
:初始狀態
- 隊列操作:
- 入隊:尾插法(CAS更新Tail)
// AQS中的入隊代碼 private Node addWaiter(Node mode) {Node node = new Node(Thread.currentThread(), mode);Node pred = tail;if (pred != null) {node.prev = pred;if (compareAndSetTail(pred, node)) {pred.next = node;return node;}}enq(node); // CAS失敗時自旋入隊return node; }
- 出隊:頭節點釋放后喚醒后繼
// 喚醒后繼節點 private void unparkSuccessor(Node node) {int ws = node.waitStatus;if (ws < 0) compareAndSetWaitStatus(node, ws, 0);Node s = node.next;if (s == null || s.waitStatus > 0) {s = null;// 從尾向前查找有效節點for (Node t = tail; t != null && t != node; t = t.prev)if (t.waitStatus <= 0) s = t;}if (s != null) LockSupport.unpark(s.thread); }
- 入隊:尾插法(CAS更新Tail)
1.2 AQS工作流程詳解(獨占模式)
1.2.1 核心執行流程
1.2.2 關鍵機制解析
- CAS無鎖操作:
// AQS更新state的核心方法 protected final boolean compareAndSetState(int expect, int update) {return unsafe.compareAndSwapInt(this, stateOffset, expect, update); }
- 通過Unsafe類直接操作內存,確保原子性
- stateOffset通過
objectFieldOffset
獲取字段偏移量
- 線程阻塞與喚醒:
- 阻塞:
LockSupport.park(this)
- 喚醒:
LockSupport.unpark(thread)
- 基于Unsafe的park/unpark,比Object.wait/notify更高效
- 阻塞:
- 隊列管理:
- 入隊:CAS尾插法,保證線程安全
- 出隊:頭節點釋放后,將后繼節點設為新頭節點
二、AQS的同步模式與核心方法
2.1 獨占模式(Exclusive Mode)
2.1.1 核心特性
- 同一時刻僅允許一個線程獲取資源
- 典型實現:ReentrantLock、ReentrantReadWriteLock.WriteLock
- 關鍵方法:
acquire(int arg)
:獲取資源,失敗則入隊等待release(int arg)
:釋放資源,喚醒后繼節點
2.1.2 狀態流轉圖
2.2 共享模式(Shared Mode)
2.2.1 核心特性
- 允許多個線程同時獲取資源
- 典型實現:Semaphore、CountDownLatch、ReentrantReadWriteLock.ReadLock
- 關鍵方法:
acquireShared(int arg)
:獲取共享資源,失敗入隊releaseShared(int arg)
:釋放共享資源,可能喚醒后繼