一、AQS的整体架构
AQS(AbstractQueuedSynchronizer)是JUC包的基石,ReentrantLock、CountDownLatch、Semaphore、ReentrantReadWriteLock都建在它上面。
核心结构:
┌─────────────────────────────────────────────┐│ AbstractQueuedSynchronizer ││ ││ ┌─────────────┐ ┌──────────────────────┐ ││ │ state (int) │◄───│ CLH Variant Queue │ ││ │ volatile │ │ (FIFO wait queue) │ ││ └─────────────┘ │ │ ││ │ head ←→ node1 ←→ │ ││ ┌─────────────┐ │ node2 ←→ node3 ←→.. │ ││ │ exclusiveOwner│ └──────────────────────┘ ││ │ (Thread) │ ││ └─────────────┘ │└─────────────────────────────────────────────┘三个核心:
volatile int state——同步状态,独占模式表示重入次数/锁占用,共享模式表示剩余许可数 CLH变体队列——FIFO双向链表,线程阻塞/唤醒的载体 CAS——所有状态变更的原子操作基础
二、Node:CLH队列的最小单元
staticfinalclassNode{// 共享模式staticfinal Node SHARED = new Node();// 独占模式staticfinal Node EXCLUSIVE = null;// 等待状态staticfinalint CANCELLED = 1; // 超时/中断,出队staticfinalint SIGNAL = -1; // 后继需要被唤醒staticfinalint CONDITION = -2; // 在Condition队列中staticfinalint PROPAGATE = -3; // 共享模式传播volatileint waitStatus; // 节点状态volatile Node prev; // 前驱volatile Node next; // 后继volatile Thread thread; // 等待线程 Node nextWaiter; // Condition队列中的后继,或共享模式下的特殊链表}设计要点:
waitStatus用volatile而非volatile int数组——每个Node独立可见,避免伪共享prev和next用volatile保证多线程下链表操作的可见性thread设为volatile:中断时需要快速找到目标线程SHARED和EXCLUSIVE用Node实例和null区分,而非枚举——省内存、省比较
CLH队列与原版CLH锁的区别
原版CLH锁是自旋锁,没有waitStatus,只靠自旋。AQS改造:
原版CLH: 每个节点自旋等前驱释放AQS CLH: 节点挂起(park),靠waitStatus+park/unpark协作唤醒关键点:
增加 waitStatus,避免无效唤醒用 LockSupport.park()替代自旋,节省CPU支持超时取消( CANCELLED状态)
三、state的CAS操作:原子性的根基
AQS所有核心方法都依赖CAS修改state:
// Unsafe直接操作privatestaticfinal Unsafe unsafe = Unsafe.getUnsafe();privatestaticfinallong stateOffset;static {try { stateOffset = unsafe.objectFieldOffset (AbstractQueuedSynchronizer.class.getDeclaredField("state")); } catch (Exception ex) { thrownew Error(ex); }}protectedfinalbooleancompareAndSetState(int expect, int update){return unsafe.compareAndSwapInt(this, stateOffset, expect, update);}为什么用Unsafe而不是AtomicInteger:
AtomicInteger底层也是Unsafe.compareAndSwapInt AQS需要更细粒度控制(加失败后的自旋重试逻辑) 直接用Unsafe少一层封装,性能更可控
CAS的重试:acquireQueued中的自旋
// 独占模式获取锁的核心循环finalbooleanacquireQueued(final Node node, int arg){boolean failed = true;try {boolean interrupted = false;for (;;) { // 自旋final Node p = node.predecessor();if (p == head && tryAcquire(arg)) { // 前驱是head且自己抢到了 setHead(node); p.next = null; // help GC failed = false;return interrupted; }if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally {if (failed) cancelAcquire(node); }}设计哲学:CAS失败不立刻park,先检查前驱状态。只有前驱是SIGNAL或CANCELLED时才park——减少无效park/unpark。
四、独占模式(Exclusive):ReentrantLock的底层
4.1 tryAcquire:获取锁的两次机会
// NonfairSync(非公平)finalbooleannonfairTryAcquire(int acquires){final Thread current = Thread.currentThread();int c = getState();if (c == 0) { // 第一次机会:锁空闲,直接CASif (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current);returntrue; } }elseif (current == getExclusiveOwnerThread()) { // 第二次机会:重入int nextc = c + acquires;if (nextc < 0) // overflowthrownew Error("Maximum lock count exceeded"); setState(nextc);returntrue; }returnfalse;}// FairSync(公平)finalbooleantryAcquire(int acquires){final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (!hasQueuedPredecessors() && // 多了一个检查:队列有没有前驱 compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current);returntrue; } }elseif (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0)thrownew Error("Maximum lock count exceeded"); setState(nextc);returntrue; }returnfalse;}公平与非公平的唯一区别:公平版在CAS之前加了hasQueuedPredecessors()检查。
staticfinalbooleanhasQueuedPredecessors(){ Node h = head; Node t = tail;return h != t && // 队列非空 (h.next == null || h.thread != Thread.currentThread());// 注意:h.next == null 说明正在初始化,不算有前驱}4.2 release:释放锁的传播
publicfinalbooleanrelease(int arg){if (tryRelease(arg)) { Node h = head;if (h != null && h.waitStatus != 0) unparkSuccessor(h); // 唤醒后继returntrue; }returnfalse;}protectedfinalbooleantryRelease(int releases){int c = getState() - releases;if (Thread.currentThread() != getExclusiveOwnerThread())thrownew IllegalMonitorStateException();boolean free = (c == 0);if (free) setExclusiveOwnerThread(null); setState(c);return free;}unparkSuccessor的传播逻辑:
privatevoidunparkSuccessor(Node node){int ws = node.waitStatus;if (ws < 0) compareAndSetWaitStatus(node, ws, 0); // 清除SIGNAL Node s = node.next;if (s == null || s.waitStatus > 0) { // s为null或已取消 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);}从tail向前扫描的设计:node.next可能已经无效(因为node被取消时next会被置为null),所以从tail倒序找到最近的非取消节点。这是AQS中为数不多的反向遍历。
五、共享模式(Shared):Semaphore/CountDownLatch的底层
5.1 tryAcquireShared:抢许可
// Semaphore的NonfairSyncprotectedinttryAcquireShared(int acquires){for (;;) {int available = getState();int remaining = available - acquires;if (remaining < 0 || compareAndSetState(available, remaining))return remaining; }}返回值含义:
>= 0:获取成功,返回剩余许可数< 0:获取失败,返回负值(绝对值=需要等待的许可数)
5.2 doAcquireShared:入队+park
privatevoiddoAcquireShared(int arg){final Node node = addWaiter(Node.SHARED); // 加共享节点boolean failed = true;try {boolean interrupted = false;for (;;) {final Node p = node.predecessor();if (p == head) {int r = tryAcquireShared(arg);if (r >= 0) { // 成功 setHeadAndPropagate(node, r); p.next = null; failed = false;return; } }if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally {if (failed) cancelAcquire(node); }}5.3 setHeadAndPropagate:共享模式的关键传播
这是共享模式与独占模式最大的不同:
privatevoidsetHeadAndPropagate(Node node, int propagate){ Node h = head; setHead(node);if (propagate > 0 || h == null || h.waitStatus < 0 || (h = head) == null || h.waitStatus < 0) { Node s = node.next;if (s == null || s.isShared()) doReleaseShared(); // 唤醒后继共享节点 }}传播逻辑:
propagate > 0:还有剩余许可,可以唤醒后继h.waitStatus < 0:原head是SIGNAL状态,需要传播唤醒时只唤醒 isShared()的节点——不唤醒独占节点,避免浪费
六、队列操作:enq的入队细节
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)) { t.next = node;return t; // 返回前驱,用于park前检查 } } }}两次CAS的设计:
第一次CAS初始化head(只在tail为null时) 第二次CAS设置tail,成功后才设置 t.next = node
为什么不先设t.next再CAS?因为如果CAS失败,t.next已经被设置了,但tail没变,其他线程可能看到不一致的状态。先CAS成功再修改next,保证原子性。
addWaiter:enq的封装
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); // 竞争失败或初始化,走enqreturn node;}七、Condition的实现:独占模式下的等待/通知
ConditionObject是AQS的内部类,本质是一个独立的CLH队列:
publicclassConditionObjectimplementsCondition, java.io.Serializable{privatestaticfinallong serialVersionUID = 1173984872572414699L;// Condition队列的头privatetransient Node firstWaiter;// Condition队列的尾privatetransient Node lastWaiter;publicfinalvoidawait()throws InterruptedException {if (Thread.interrupted())thrownew InterruptedException(); Node node = addConditionWaiter(); // 加入Condition队列int savedState = fullyRelease(node); // 释放锁,state=0int interruptMode = 0;while (!isOnSyncQueue(node)) { // 不在AQS主队列时park LockSupport.park(this);if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)break; }if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT;if (node.nextWaiter != null) // clean up unlinkCancelledWaiters();if (interruptMode != 0) reportInterruptAfterWait(interruptMode); }private Node addConditionWaiter(){ Node t = lastWaiter;if (t != null && t.waitStatus != Node.CONDITION) { unlinkCancelledWaiters(); t = lastWaiter; } Node node = new Node(Thread.currentThread(), Node.CONDITION);if (t == null) firstWaiter = node;else t.nextWaiter = node; lastWaiter = node;return node; }publicfinalvoidsignal(){if (!isHeldExclusively())thrownew IllegalMonitorStateException(); Node first = firstWaiter;if (first != null) doSignal(first); // 移动到AQS主队列 }privatevoiddoSignal(Node first){do {if ((firstWaiter = first.nextWaiter) == null) lastWaiter = null; first.nextWaiter = null; } while (!transferForSignal(first) && (first = firstWaiter) != null); }finalbooleantransferForSignal(Node node){if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))returnfalse; // CAS失败,说明已被取消或signal Node p = enq(node); // 加入AQS主队列int ws = p.waitStatus;if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread);returntrue; }}关键设计:
Condition队列节点的waitStatus=CONDITION(-2),不在主队列的唤醒逻辑中 await时先释放锁(fullyRelease),再park——保证不占着锁等待 signal时把节点从Condition队列移到AQS主队列尾部,然后unpark
八、cancelAcquire:取消节点的清理
privatevoidcancelAcquire(Node node){if (node == null)return; node.thread = null; // 断引用 Node pred = node.prev;if (pred == null)return; node.waitStatus = Node.CANCELLED;if (node.next == null || node.next.waitStatus > 0) {// 找到有效后继 Node s = node.next;if (s == null)for (Node t = tail; t != null && t != node; t = t.prev)if (t.waitStatus <= 0) s = t;if (s != null) compareAndSetNext(pred, node, s); } else {// 后继正常,前驱跳过自己指向后继if (pred != null && pred.waitStatus <= 0) { Node succ = node.next;if (succ != null && succ.waitStatus <= 0) compareAndSetNext(pred, node, succ); } }}双向链表删除的难点:多线程同时操作,用CAS逐个更新next指针,而非一次性断开——保证线程安全。
九、shouldParkAfterFailedAcquire:park前的最后判断
privatestaticbooleanshouldParkAfterFailedAcquire(Node pred, Node node){int ws = pred.waitStatus;if (ws == Node.SIGNAL)returntrue; // 前驱已标记SIGNAL,可以安全parkif (ws > 0) { // 前驱CANCELLEDdo { node.prev = pred = pred.prev; } while (pred.waitStatus > 0); // 跳过所有取消节点 pred.next = node; } else { compareAndSetWaitStatus(pred, ws, Node.SIGNAL); // 给前驱标记SIGNAL }returnfalse; // 标记完SIGNAL后再自旋一次,不park}为什么标记SIGNAL后不立即park? 因为CAS可能失败(其他线程已经在改pred的waitStatus了),需要再循环一次确认。这就是"惰性标记"——不到park那一刻不做多余的事。
十、总结一下
10.1 为什么是CLH而不是MCS?
AQS选CLH是因为:需要从tail向前扫描(找有效节点),prev引用天然支持。MCS的hint机制在这种场景下没有优势。
10.2 为什么用volatile而非synchronized?
AQS队列操作完全依赖volatile+CAS,没有任何synchronized块。原因:
synchronized在竞争激烈时涉及内核态切换,开销大 volatile+CAS在无竞争时是单指令,有竞争时自旋,延迟更可控 但代价是代码复杂度极高——AQS源码约2000行,全是细节
10.3 为什么state用int而非AtomicInteger?
int+CAS比AtomicInteger少一层对象头和volatile字段的间接访问 AQS自己封装了 compareAndSetState,可以在失败后加自旋逻辑独占模式下state还表示重入次数(可>1),语义上不适合AtomicInteger的"单一值"语义
10.4 模板方法模式的精髓
// AQS定义骨架publicabstractclassAbstractQueuedSynchronizer{protectedbooleantryAcquire(int){ thrownew UnsupportedOperationException(); }protectedbooleantryRelease(int){ thrownew UnsupportedOperationException(); }protectedinttryAcquireShared(int){ thrownew UnsupportedOperationException(); }protectedbooleantryReleaseShared(int){ thrownew UnsupportedOperationException(); }// 子类只需实现这四个方法,其余全部复用publicfinalvoidacquire(int arg){ ... }publicfinalvoidrelease(int arg){ ... }}ReentrantLock只需实现tryAcquire和tryRelease,Semaphore只需实现tryAcquireShared和tryReleaseShared。这是"策略模式+模板方法"的经典结合——AQS负责队列管理、park/unpark、CAS,子类只负责什么时候能拿到锁。
夜雨聆风