深入解析 AQS 源码
一、前言
在 Java 并发编程的世界里,AbstractQueuedSynchronizer
(简称 AQS )是 JUC 包的核心基础组件。常见的同步工具类,例如 ReentrantLock
、Semaphore
、CountDownLatch
、FutureTask
等,底层都依赖 AQS 来实现。理解 AQS 的设计和源码,可以帮助我们透彻掌握 Java 并发工具的原理。
二、AQS 的核心思想
AQS 的核心是 同步状态 + 队列管理:
- state 变量 :通过一个
volatile int state
表示同步状态(例如锁是否被占用,剩余许可证数量等)。 - FIFO 队列:使用一个变种的 CLH 双向队列来管理等待的线程。
- 模板方法模式:获取/释放锁的通用逻辑由 AQS 实现,具体的 tryAcquire/tryRelease 逻辑交由子类实现。
三、源码核心结构
1. state 的操作
AQS 提供了对同步状态的安全操作:
java
protected final int getState() { return state; }
protected final void setState(int newState) { state = newState; }
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
这里通过 CAS 保证并发下的原子操作。
2. 独占模式与共享模式
AQS 同时支持两种抽象方法模式:
-
独占模式 :典型代表
ReentrantLock
。acquire(int arg)
/tryAcquire(int arg)
:定义模板方法,由子类实现,其他也是release(int arg)
/tryRelease(int arg)
:定义模板方法,由子类实现,其他也是
-
共享模式 :典型代表
Semaphore
、CountDownLatch
。acquireShared(int arg)
/tryAcquireShared(int arg)
releaseShared(int arg)
/tryReleaseShared(int arg)
3. acquire 的核心流程(独占模式)
java
public final void acquire(int arg) {
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
执行流程:
- tryAcquire:尝试获取锁,子类实现。
- 如果失败,addWaiter 将线程加入等待队列。
- acquireQueued:在队列中自旋阻塞,直到前驱节点释放资源。
4. Node 节点(CLH 队列)
队列中的线程由 Node
表示:
java
static final class Node {
static final Node SHARED = new Node();
static final Node EXCLUSIVE = null;
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
}
waitStatus
标识节点状态(如 SIGNAL、CANCELLED)。- 通过
prev/next
链接形成双向队列。
四、典型应用
1. ReentrantLock(独占模式)
java
static final class NonfairSync extends Sync {
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
// 可重入逻辑
}
}
ReentrantLock
通过重写 tryAcquire
来定义获取锁的逻辑,其他排队/阻塞流程交由 AQS 完成。
2. CountDownLatch(共享模式)
java
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
protected boolean tryReleaseShared(int releases) {
for (;;) {
int c = getState();
if (c == 0) return false;
int nextc = c - 1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
await()
依赖acquireShared
,当 state=0 时继续执行。countDown()
调用releaseShared
,逐步减少计数,直到为 0 时唤醒所有等待线程。
五、总结
- AQS 核心 :
state
表示同步状态,CLH 队列管理线程,模板方法模式解耦逻辑。 - 独占/共享模式:灵活支持多种并发工具。
- 典型实现 :
ReentrantLock
、Semaphore
、CountDownLatch
等。 - 模板方法:AQS只是定义对应的tryrelease、tryAcquire等try-xxx抽象方法,对应的方法都是由对应的实现类来实现,并且不强制子类去实现,但是使用时候必须重写,否则报错。
AQS 的设计极其优雅,它把"排队 + 阻塞 + 唤醒 + 状态管理"抽象了出来,真正实现了并发工具类的可复用性。理解 AQS,等于掌握了 JUC 的灵魂。