AQS
AQS(AbstractQueuedSynchronizer):Java 同步框架的基石
AQS(AbstractQueuedSynchronizer,队列同步器)是 Java 并发包(JUC)的核心基础组件,为 ReentrantLock、Semaphore、CountDownLatch 等同步工具提供统一的底层支持。它通过同步状态管理和FIFO 等待队列实现了高效的线程同步机制。本文将深入解析 AQS 的设计原理、核心组件及工作流程。
AQS 的核心设计思想
AQS 的核心目标是简化同步组件的实现,其设计基于模板方法模式:
- 子类通过继承 AQS 并实现特定抽象方法(如
tryAcquire、tryRelease)来定义同步状态的获取与释放规则; - AQS 自身实现了队列管理、线程阻塞 / 唤醒等通用逻辑,无需子类重复开发。
核心组件
- 同步状态(state):一个
volatile int变量,用于表示资源的占有状态(如 0 表示未占用,1 表示已占用); - FIFO 等待队列:双向链表结构,存储等待获取资源的线程节点;
- 条件队列(Condition):与
Lock配合使用,实现线程间的条件等待。
AQS 核心源码解析

同步状态(state)
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements Serializable {
// 同步状态,volatile保证可见性
private volatile int state;
// 获取当前状态
protected final int getState() { return state; }
// 设置状态(无原子性保证)
protected final void setState(int newState) { state = newState; }
// CAS设置状态(保证原子性)
protected final boolean compareAndSetState(int expect, int update) {
return UNSAFE.compareAndSwapInt(this, stateOffset, expect, update);
}
}
状态的意义:
- 对于
ReentrantLock,state表示重入次数(0:未锁定;n>0:被锁定 n 次); - 对于
Semaphore,state表示剩余许可数; - 对于
CountDownLatch,state表示计数器值。
FIFO 等待队列(同步队列)
等待队列是 AQS 的核心,用于存储因获取资源失败而阻塞的线程。队列由Node节点组成,结构如下:
Node 节点结构
static final class Node {
// 共享模式标记(用于Semaphore等)
static final Node SHARED = new Node();
// 独占模式标记(用于ReentrantLock等)
static final Node EXCLUSIVE = null;
// 节点状态(等待状态)
volatile int waitStatus;
static final int CANCELLED = 1; // 已取消(超时或中断)
static final int SIGNAL = -1; // 需唤醒后继节点
static final int CONDITION = -2; // 在条件队列中
static final int PROPAGATE = -3; // 共享模式下的传播
// 前驱节点
volatile Node prev;
// 后继节点
volatile Node next;
// 节点关联的线程
volatile Thread thread;
// 条件队列中的后继节点(或共享模式标记)
Node nextWaiter;
}
队列结构
head -> Node1 -> Node2 -> ... -> tail
head:头节点(哨兵节点,无实际线程);tail:尾节点(最新加入的节点);- 节点通过
prev和next形成双向链表。
独占模式下的资源获取与释放
以ReentrantLock的独占锁为例,解析 AQS 的核心流程。
获取资源:acquire(int arg)
public final void acquire(int arg) {
// 1. 尝试获取资源(tryAcquire由子类实现)
// 2. 失败则加入等待队列(addWaiter)
// 3. 在队列中阻塞等待(acquireQueued)
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) {
selfInterrupt(); // 若被中断,恢复中断状态
}
}
tryAcquire:子类实现,定义独占模式下的资源获取逻辑(如ReentrantLock判断state是否为 0,是则 CAS 设置为 1)。addWaiter:将当前线程封装为 Node,通过 CAS 加入队列尾部: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); // 队列为空或CAS失败时,自旋入队 return node; }acquireQueued:节点在队列中自旋等待,直到获取资源或被取消:final 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; } // 判断是否可以阻塞,若可以则park当前线程 if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) { interrupted = true; } } } finally { if (failed) cancelAcquire(node); // 获取失败,取消节点 } }
释放资源:release(int arg)
public final boolean release(int arg) {
// 1. 尝试释放资源(tryRelease由子类实现)
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0) {
unparkSuccessor(h); // 2. 唤醒后继节点
}
return true;
}
return false;
}
tryRelease:子类实现,定义资源释放逻辑(如ReentrantLock将state减 1,为 0 时表示完全释放)。unparkSuccessor:唤醒后继节点(移除取消节点,调用LockSupport.unpark)。
条件队列(Condition)
AQS 内部类ConditionObject实现了Condition接口,与Lock配合实现线程间的条件等待(类似synchronized的wait/notify)。
核心方法
await():将当前线程加入条件队列,释放锁并阻塞;signal():将条件队列的首节点转移到同步队列,等待获取锁;signalAll():转移所有条件队列节点到同步队列。
工作流程
- 线程获取锁后,调用
await()进入条件队列并释放锁; - 其他线程调用
signal(),将条件队列节点转移到同步队列; - 同步队列中的节点竞争锁,获取后继续执行。
LockSupport 工具类
AQS 通过LockSupport实现线程的阻塞与唤醒,其核心方法:
park():阻塞当前线程(需unpark唤醒);unpark(Thread t):唤醒指定线程(提前调用可设置 “许可”,使后续park不阻塞)。
LockSupport相比wait/notify的优势:
- 无需在同步块中调用;
- 支持中断响应;
- 避免虚假唤醒(通过 “许可” 机制)。
AQS 的应用:同步组件举例
ReentrantLock(独占锁)
tryAcquire:判断state是否为 0,是则 CAS 设置为 1(非公平锁);或检查是否为当前线程,是则state++(重入)。tryRelease:state--,为 0 时释放锁并返回true。
Semaphore(信号量)
- 共享模式:多个线程可同时获取许可。
tryAcquireShared:state减去请求的许可数,若 >=0 则成功。tryReleaseShared:state加上释放的许可数,唤醒后续节点。
CountDownLatch(倒计时器)
tryAcquireShared:若state为 0 则成功,否则失败并加入队列。countDown():调用tryReleaseShared,state--,为 0 时唤醒所有等待线程。
AQS 的核心优势
- 通用性:统一实现队列管理、线程阻塞等逻辑,简化同步组件开发;
- 高效性:基于 CAS 和自旋锁,减少锁竞争带来的性能损耗;
- 灵活性:支持独占 / 共享模式,可扩展出多种同步工具;
- 安全性:通过 volatile 和 CAS 保证状态的线程可见性与原子性。