AQS 原理:AbstractQueuedSynchronizer¶
一、AQS 是什么¶
AQS(抽象队列同步器)是 JUC 锁的基础框架。ReentrantLock、CountDownLatch、Semaphore、ReentrantReadWriteLock 都基于它。
二、核心结构¶
1. state 状态¶
- 0:无锁。
-
0:被锁,值是重入次数。
不同实现对 state 解释不同: - ReentrantLock:持有数。 - Semaphore:剩余许可数。 - CountDownLatch:计数。
2. CLH 队列¶
双向链表,存等待锁的线程:
每个 node 包一个线程,node 间通过 prev/next 连接。
3. 独占 / 共享¶
- 独占:ReentrantLock,一次一个线程。
- 共享:Semaphore、CountDownLatch,多个线程同时通过。
三、核心方法¶
模板方法模式¶
AQS 定义骨架,子类重写:
tryAcquire(int):尝试获取锁(独占)。tryRelease(int):尝试释放锁(独占)。tryAcquireShared(int):尝试获取共享。tryReleaseShared(int):尝试释放共享。
骨架方法¶
acquire(int):获取锁,失败进队列。release(int):释放锁,唤醒下一个。
四、acquire 流程¶
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
tryAcquire:子类实现,CAS 抢锁。- 失败:
addWaiter把当前线程包成 node 加到队尾。 acquireQueued:自旋检查前驱是不是 head,是就再 tryAcquire,否则挂起。
五、release 流程¶
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h); // 唤醒 head 的下一个节点
return true;
}
return false;
}
tryRelease:子类实现,state 减到 0。- 唤醒 head 的后继节点。
六、为什么用 AQS¶
- 队列管理、阻塞/唤醒、中断处理都封装好了。
- 子类只需要实现 state 的获取和释放。
- 避免每个锁都重复写队列逻辑。
高频追问
- state 是 volatile,保证可见性。
- CLH 队列是变体(原版不存储前驱指针)。
- 队列不保证公平:新线程可能和队列头线程竞争。