Java 並發包(JUC)中的 ReentrantLock 是構建高併發系統的基石。其公平鎖實現基於 AQS(AbstractQueuedSynchronizer)框架,通過 CLH 隊列實現嚴格的先來先得(FIFO)調度。本文基於 JDK 1.7.0_40 源碼,從 lock() 入口出發,層層剖析 acquire() → tryAcquire() → addWaiter() → acquireQueued() 的完整獲取鏈路,還原公平鎖「不插隊、按序等待、精準喚醒」的核心邏輯。
ReentrantLock (實現 Lock 接口)
└─ sync: Sync (組合關係,核心同步器)
├─ FairSync (公平鎖實現)
└─ NonfairSync (非公平鎖實現)
└─ AbstractQueuedSynchronizer (AQS,模板方法框架)
└─ AbstractOwnableSynchronizer (持有 exclusiveOwnerThread)
ReentrantLock 通過構造函數注入 FairSync 或 NonfairSync 決定公平性Sync 繼承 AQS,封裝鎖狀態(state)、持有者線程(exclusiveOwnerThread)及核心操作acquire/release),子類實現 tryAcquire/tryRelease 定制語義// FairSync.lock()
final void lock() {
acquire(1);
}
// AQS.acquire()
public final void acquire(int arg) {
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
1 代表「獲取一個鎖許可」。可重入鎖中,state 表示重入次數:0=空閒,1=首次獲取,2=重入一次...// FairSync.tryAcquire()
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) { // 鎖空閒
if (!hasQueuedPredecessors() && // 【關鍵】無前驅等待者
compareAndSetState(0, acquires)) { // CAS 設置狀態
setExclusiveOwnerThread(current);
return true;
}
} else if (current == getExclusiveOwnerThread()) { // 重入
int nextc = c + acquires;
if (nextc < 0) throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
!hasQueuedPredecessors() 確保只有在「無前驅等待線程」時才嘗試 CAS 獲取,杜絕插隊state,無需進隊列compareAndSetState 基於 Unsafe.CAS,保證狀態更新原子性public final boolean hasQueuedPredecessors() {
Node t = tail, h = head, s;
return h != t && ((s = h.next) == null || s.thread != Thread.currentThread());
}
head != tail:隊列非空h.next == null:頭節點尚未關聯後繼(初始化瞬間)h.next.thread != current:後繼節點不是當前線程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)) { // CAS 設置尾節點
pred.next = node;
return node;
}
}
enq(node); // 隊列空或 CAS 失敗:完整入隊邏輯
return node;
}
private Node enq(final Node node) {
for (;;) { // 自旋直到入隊成功
Node t = tail;
if (t == null) { // 隊列未初始化
if (compareAndSetHead(new Node())) // 創建哨兵頭節點
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) { // CAS 更新尾節點
t.next = node;
return t;
}
}
}
}
head 為哨兵節點(不關聯線程),tail 指向最後等待者enq() 自旋保證最終入隊Node.EXCLUSIVE 標記獨占模式,nextWaiter=nullfinal boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor(); // 獲取前驅節點
if (p == head && tryAcquire(arg)) { // 前驅是頭節點且嘗試獲取成功
setHead(node); // 當前節點成為新頭節點
p.next = null; // 斷開舊頭節點引用(助 GC)
failed = false;
return interrupted; // 返回是否被中斷過
}
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
interrupted = true; // 記錄中斷狀態
}
} finally {
if (failed) cancelAcquire(node); // 異常退出取消節點
}
}
p == head 確保只有前驅釋放鎖並喚醒後,當前節點才嘗試獲取,嚴格 FIFOsetHead(node) 將當前節點設置為頭節點(哨兵),原節點斷開引用private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL) return true; // 前驅已發出喚醒信號,可安全阻塞
if (ws > 0) { // 前驅已取消
do { node.prev = pred = pred.prev; } // 向前跳過取消節點
while (pred.waitStatus > 0);
pred.next = node;
} else { // ws == 0 或 PROPAGATE
compareAndSetWaitStatus(pred, ws, Node.SIGNAL); // 設置前驅為 SIGNAL
}
return false; // 本輪不阻塞,下輪重試
}
SIGNAL:前驅已準備好喚醒後繼,返回 true → 阻塞CANCELLED (>0):前驅取消,跳過取消節點重新鏈接,返回 false → 下輪重試0/PROPAGATE:CAS 設置前驅為 SIGNAL,返回 false → 下輪重試private final boolean parkAndCheckInterrupt() {
LockSupport.park(this); // 阻塞當前線程
return Thread.interrupted(); // 返回並清除中斷狀態
}
LockSupport.park() 而非 Object.wait(),無需持有監視器鎖,輕量級unpark() 或 其他線程 interrupt()Thread.interrupted() 返回中斷狀態並清除標誌,故需在外層記錄private static void selfInterrupt() {
Thread.currentThread().interrupt(); // 重新設置中斷標誌
}
acquireQueued 中,若線程被中斷喚醒但尚未獲取鎖(因前驅未釋放),中斷標誌被 interrupted() 清除。最終獲取鎖後,調用 selfInterrupt() 恢復中斷狀態,保證上層代碼能感知中斷static final class Node {
volatile int waitStatus; // 節點狀態:CANCELLED(1), SIGNAL(-1), CONDITION(-2), PROPAGATE(-3), 0
volatile Node prev; // 前驅節點
volatile Node next; // 後繼節點
volatile Thread thread; // 關聯線程
Node nextWaiter; // 條件隊列指針 / 模式標記 (SHARED/EXCLUSIVE)
final boolean isShared() { return nextWaiter == SHARED; }
final Node predecessor() { Node p = prev; if (p==null) throw new NPE(); return p; }
}
Thread A (新請求) CLH 隊列 (Head=H, Tail=T) Thread B (持有鎖)
│ │ │
├─ lock() → acquire(1) │ │
├─ tryAcquire(1) → false │ │
├─ addWaiter(EXCLUSIVE) │ │
│ └─ 節點A入隊: H ↔ ... ↔ T ↔ A │ │
├─ acquireQueued(A) │ │
│ ├─ p = A.prev (T) │ │
│ ├─ p != head → shouldPark... │ │
│ │ └─ 設置 T.waitStatus=SIGNAL│ │
│ ├─ parkAndCheckInterrupt() │ │
│ │ └─ LockSupport.park() → 阻塞 │
│ │ │
│ │ Thread B 釋放鎖 │
│ │ ├─ unlock() │
│ │ ├─ release(1) │
│ │ ├─ tryRelease→true │
│ │ ├─ unparkSuccessor(H)│
│ │ │ └─ unpark(A) │
│ │ │ │
│ ├─ park() 返回 │ │
│ ├─ p = A.prev (H) │ │
│ ├─ p == head && tryAcquire→true│ │
│ ├─ setHead(A) // A 成為新頭 │ │
│ └─ 獲得鎖,返回 │ │
acquire/release),子類實現語義(tryAcquire/tryRelease),waitStatus 驅動協作prev/next 支持 O(1) 入隊、出隊與取消節點清理hasQueuedPredecessors() + p == head 雙重把關,嚴格 FIFO,犧牲吞吐換取無飢餓park/interrupted/selfInterrupt 三部曲,確保中斷信號不丟失、不誤觸發wait/notify,無需監視器,語義更清晰(許可證模型)公平鎖獲取流程雖代碼量大,但邏輯清晰:嘗試快速路徑 → 入隊排隊 → 自旋檢查前驅狀態 → 阻塞等待喚醒 → 獲取鎖更新頭節點。掌握這一流程,不僅能讀懂 JUC 所有同步器(Semaphore、CountDownLatch、ReentrantReadWriteLock)的底層邏輯,更能在高併發系統調優、死鎖排查、自定義同步器開發中得心應手。