在 java.util.concurrent 并发包中,AbstractQueuedSynchronizer (AQS) 是构建众多同步器(如 ReentrantLock、Semaphore、CountDownLatch)的基石框架。深入理解其内部工作原理,是掌握 Java 高级并发编程的关键。
尽管AQS源码结构复杂,但其核心机制可以清晰地归纳为三个部分:状态(State)、FIFO队列和获取/释放方法。本文将围绕这三要素,系统性地解析AQS的设计精髓。
一、状态(State):同步语义的通用寄存器
AQS 内部通过一个名为 state 的 volatile 整型变量来管理同步状态:
private volatile int state;
1.1 state的语义由子类定义
state 的具体含义取决于AQS子类的实现逻辑:
- ReentrantLock:
state 表示锁的重入次数。初始为0(未锁定),每重入一次加1,释放时减1。只有当 state == 0 时,锁才被完全释放。
- Semaphore:
state 表示当前可用的许可证数量。acquire() 尝试减少 state,release() 则增加它。
- CountDownLatch:
state 表示需要倒数的次数。每次 countDown() 将其减1,当减至0时,所有等待线程被唤醒。
因此,state 是AQS用来实现不同同步语义的、可复用的核心状态字段。
1.2 state的线程安全保证
由于 state 会被多线程并发访问和修改,AQS提供了两种线程安全的更新方式:
compareAndSetState(int expect, int update): 基于 CAS (Compare-And-Swap) 操作实现原子性更新,适用于“先读取旧值,再计算新值”的场景,是 无锁编程 的典型应用。
setState(int newState): 直接赋值。虽然看似简单,但由于 state 由 volatile 修饰,且该方法通常用于“覆盖写入”(不依赖当前值),因此在特定上下文中是线程安全的。
核心总结:volatile 保证可见性,CAS保证原子性,配合合理的 API 使用设计,共同实现了 state 的高效、安全管理。
二、FIFO队列:等待线程的调度中心
当线程尝试获取资源(锁、许可证等)失败时,AQS不会让它立即自旋浪费CPU,而是将其封装成一个节点(Node),加入一个先进先出(FIFO)的CLH变种队列中进行管理。
head: 指向队列头部的虚拟节点或当前持有资源的线程节点。
tail: 指向队列尾部,新加入的等待节点会被链接到此处。

(图片来源:Doug Lea 论文《The java.util.concurrent Synchronizer Framework》)
维护这个队列需要处理高度复杂的并发场景:多线程安全地入队/出队、管理节点的多种状态(如SIGNAL、CONDITION)、以及通过 LockSupport.park/unpark 精确控制线程的阻塞与唤醒。
AQS的巧妙之处在于,它将“线程如何排队”、“何时唤醒下一个线程”这些通用且复杂的逻辑完全封装在内部。作为框架使用者或子类开发者,只需聚焦于判断“当前状态是否允许获取资源”这一业务逻辑。这种设计极大地简化了自定义同步器的实现难度,是理解 并发与同步 底层机制的重要案例。
三、获取/释放方法:模板方法模式的典范
AQS是一个抽象类,它定义了两类核心的模板方法,而将其中最关键的一步——判断获取/释放条件——留给子类实现。
3.1 获取资源(acquire)
典型方法如 acquire(int arg)(独占式)和 acquireShared(int arg)(共享式)。以 acquire 为例,其标准流程如下:
- 调用子类实现的
tryAcquire(int arg) 方法尝试获取。
- 若成功,则直接返回,线程继续执行。
- 若失败,则将当前线程封装为Node加入等待队列,并可能进入阻塞状态。
应用示例:
ReentrantLock.lock() -> 最终调用 acquire(1)
Semaphore.acquire() -> 最终调用 acquireShared(1)
CountDownLatch.await() -> 最终调用 acquireSharedInterruptibly(1)
3.2 释放资源(release)
典型方法如 release(int arg)(独占式)和 releaseShared(int arg)(共享式)。流程相对直接:
- 调用子类实现的
tryRelease(int arg) 方法尝试释放并更新 state。
- 若释放成功,则AQS负责唤醒队列中合适的等待线程(通常是后继节点)。
应用示例:
ReentrantLock.unlock() -> 最终调用 release(1)
Semaphore.release() -> 最终调用 releaseShared(1)
CountDownLatch.countDown() -> 最终调用 releaseShared(1)
设计模式洞察:这正是模板方法模式的经典应用。AQS定义了算法骨架(入队、出队、阻塞、唤醒),而将算法中变化的部分(tryAcquire/tryRelease)延迟到子类中实现,实现了公共逻辑的最大化复用。
总结:三位一体的并发基石
AQS通过三大核心组件的协同工作,为Java并发库提供了强大而灵活的底层支持:
| 组件 |
核心作用 |
设计特点 |
| State |
承载同步状态 |
volatile int,语义灵活,是同步控制的“数据中枢” |
| FIFO队列 |
管理竞争失败的线程 |
线程安全的双向链表,实现了公平的等待与高效的调度 |
| 获取/释放方法 |
定义同步规则 |
采用模板方法模式,分离了通用流程与特定策略 |
理解AQS,就如同掌握了Java并发引擎的构造蓝图。它不仅是 ReentrantLock、Semaphore 等工具类的基础,其设计思想也对理解和构建其他高并发组件具有极高的参考价值。