承接上篇獨占鎖分析,本文以 CountDownLatch 為切入點,深度剖析 AQS 共享鎖實現機制:節點類型區分、狀態傳播、自旋優化與超時控制。
public CountDownLatch(int count) {
sync = new Sync(count);
}
static final class Sync extends AbstractQueuedSynchronizer {
Sync(int count) { setState(count); } // state = 計數器初值
}
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
調用鏈:acquireSharedInterruptibly → tryAcquireShared → doAcquireSharedInterruptibly
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1; // state==0 成功,否則失敗
}
private void doAcquireSharedInterruptibly(int arg) throws InterruptedException {
final Node node = addWaiter(Node.SHARED); // 標記為共享節點
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquireShared(arg) >= 0) {
setHeadAndPropagate(node, arg); // 關鍵:傳播喚醒
p.next = null;
failed = false;
return;
}
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed) cancelAcquire(node);
}
}
private void setHeadAndPropagate(Node node, int propagate) {
Node h = head;
setHead(node); // CAS 更新頭節點
if (propagate > 0 || h == null || h.waitStatus < 0 ||
(h = head) == null || h.waitStatus < 0) {
Node s = node.next;
if (s == null || s.isShared())
doReleaseShared(); // 喚醒下一個共享節點
}
}
private void doReleaseShared() {
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue;
unparkSuccessor(h); // 喚醒後繼節點
} else if (ws == 0 && !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue;
}
if (h == head) break;
}
}
unparkSuccessor 喚醒 Node2tryAcquireShared → 成功 → 成為頭節點 → 喚醒 Node3
public void countDown() {
sync.releaseShared(1);
}
protected boolean tryReleaseShared(int releases) {
for (;;) {
int c = getState();
if (c == 0) return false;
if (compareAndSetState(c, c - releases)) // CAS 遞減
return c - releases == 0; // 歸零返回 true 觸發傳播
}
}
| 方法 | 特性 |
|---|---|
| acquireShared | 忽略中斷 |
| acquireSharedInterruptibly | 響應中斷 |
| tryAcquireShared | 非阻塞嘗試 |
| acquireSharedNanos | 超時控制(含自旋閾值 1000ns) |
if (nanosTimeout > spinForTimeoutThreshold) // 1000ns
LockSupport.parkNanos(this, nanosTimeout);
else
// 短超時直接自旋,避免上下文切換開銷
tryAcquire/Release)由子類定義state 可代表鎖計數、信號量許可、倒數閂計數、讀寫鎖狀態ReentrantReadWriteLock 同時使用獨占(寫)與共享(讀) APIFutureTask (JDK 1.6) 使用獨占 API 實現結果獲取阻塞Semaphore 使用共享 API 實現許可證控制CyclicBarrier 組合鎖與條件實現攔截點