一、什么是 AQS?
AbstractQueuedSynchronizer(简称 AQS)是 Java 并发包 java.util.concurrent.locks 中的一个核心同步框架,用于构建锁和同步器,如:
- ReentrantLock
 - ReentrantReadWriteLock
 - CountDownLatch
 - Semaphore
 - FutureTask
 
AQS 通过一个FIFO 双向等待队列(CLH 队列)管理线程的同步状态,使开发者可以专注于同步逻辑,而不必关注线程的调度、阻塞、唤醒等底层细节。
二、AQS 的核心设计
1. 核心成员变量
private volatile int state;       // 同步状态
private transient Node head;      // 队列头节点
private transient Node tail;      // 队列尾节点
 
state:用来表示资源的占用状态(例如是否被锁定、可用信号量数等);head和tail:维护一个 CLH 等待队列,用于管理阻塞的线程。
2. 核心方法(模板方法)
AQS 提供一系列模板方法用于子类实现:
// 共享模式
protected int tryAcquireShared(int arg);
protected boolean tryReleaseShared(int arg);// 独占模式
protected boolean tryAcquire(int arg);
protected boolean tryRelease(int arg);
 
子类需要实现这些方法,以控制对资源的获取与释放逻辑。
三、AQS 工作流程
1. 获取锁(以独占模式为例)
lock.lock() → tryAcquire() 尝试获取 → 获取失败 → 加入 CLH 队列 → park(阻塞)→ 被唤醒时再次尝试
 
流程:
- 调用 
tryAcquire()尝试获取资源; - 如果失败,则将当前线程封装为 
Node加入等待队列; - 阻塞(park)当前线程;
 - 资源释放后,唤醒下一个等待线程。
 
2. 释放锁
unlock() → tryRelease() 成功 → 唤醒队列中下一个线程
 
tryRelease()将state设置为 0;- 然后调用 
unparkSuccessor()唤醒下一个线程。 
四、独占模式 vs 共享模式
| 模式 | 描述 | 
|---|---|
| 独占模式 | 同一时刻只能有一个线程访问,如 ReentrantLock | 
| 共享模式 | 多个线程可以共享资源,如 Semaphore、CountDownLatch | 
AQS 区分这两种模式,并分别处理入队、出队、唤醒等逻辑。
五、CLH 队列机制
AQS 使用一种变体的 CLH(Craig–Landin–Hagersten)同步队列 实现线程排队。
队列结构:
head -> Node1 -> Node2 -> ... -> tail
 
- 每个节点是一个线程的等待快照;
 - 新线程失败后加入尾部,前驱释放时唤醒后继;
 - 自旋或 park 阻塞等待。
 
六、典型用法示例
自定义锁的基本写法
class MyLock extends AbstractQueuedSynchronizer {protected boolean tryAcquire(int arg) {return compareAndSetState(0, 1);}protected boolean tryRelease(int arg) {setState(0);return true;}public void lock() {acquire(1); // 内部调用 tryAcquire + 入队逻辑}public void unlock() {release(1);}
}
 
CountDownLatch 原理
- 使用共享模式;
 - 每次 
countDown()执行releaseShared(-1); await()会在 state = 0 前阻塞。
七、AQS 的优点
| 优点 | 说明 | 
|---|---|
| 封装阻塞逻辑 | 使用 LockSupport 封装了 park/unpark | 
| 可复用性强 | 模板方法模式,便于自定义同步器 | 
| 队列高效 | FIFO 队列实现公平性,性能稳定 | 
| 支持两种模式 | 支持共享和独占资源控制 | 
八、注意点 & 问题排查
- 死锁:一定要在 
try...finally中释放锁; - state 状态:设计时需合理设置 state 的含义(计数、二进制等);
 - CLH 队列泄露:释放时未正确调用 
unpark会导致阻塞线程永久等待; - 性能瓶颈:高并发下需注意锁竞争,考虑使用 
StampedLock或乐观锁优化。 
九、AQS 应用类汇总
| 类名 | 模式 | 简介 | 
|---|---|---|
| ReentrantLock | 独占 | 可重入、可中断、公平/非公平 | 
| Semaphore | 共享 | 控制资源访问数目 | 
| CountDownLatch | 共享 | 等待所有任务完成 | 
| ReentrantReadWriteLock | 共享 + 独占 | 高效读写分离 | 
| FutureTask | 独占 | 控制异步任务状态 | 
| AbstractQueuedSynchronizer | 基类 | 框架级同步器 | 
十、总结
- AQS 是构建 Java 同步工具的核心;
 - 通过队列管理线程阻塞与唤醒;
 - 使用模板方法封装了多种模式;
 - 掌握 AQS = 掌握 Java 并发的核心原理。
 
补充:AQS 源码流程图解析 + ReentrantLock 实战源码
一、AQS 获取锁(acquire)源码流程
public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt();
}
 
流程图解:
             acquire()│┌───────┴────────┐↓                ↓tryAcquire()     // 自定义尝试获取(成功返回true)     (失败)↓                ↓return      addWaiter(Node.EXCLUSIVE)↓入队列构造双向链表↓acquireQueued(node, arg)↓while(前驱不是head || 不能获取锁)↓        ↓park()   tryAcquire()↓获取成功 → 设置head → unpark下一个
 
二、AQS 释放锁(release)源码流程
public final boolean release(int arg) {if (tryRelease(arg)) {Node h = head;if (h != null && h.waitStatus != 0)unparkSuccessor(h);return true;}return false;
}
 
流程图解:
            release()│tryRelease()│是否成功释放?↓   ↑true  false↓获取 head↓唤醒下一个节点(unpark)
 
三、ReentrantLock 是怎么用 AQS 实现的?
源码结构简图:
public class ReentrantLock implements Lock {abstract static class Sync extends AbstractQueuedSynchronizer {// 核心逻辑都在此子类中}final Sync sync;
}
 
ReentrantLock 的两个实现版本:
| 类型 | 类名 | 特点 | 
|---|---|---|
| 非公平锁(默认) | NonfairSync | 直接尝试获取锁,抢占式,性能好 | 
| 公平锁 | FairSync | 排队获取,按顺序,不插队,公平但慢一些 | 
tryAcquire 的实现(非公平锁)
protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {// 尝试直接 CAS 获取锁if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}} else if (current == getExclusiveOwnerThread()) {// 可重入,加重入次数int nextc = c + acquires;setState(nextc);return true;}return false;
}
 
tryRelease 的实现
protected final boolean tryRelease(int releases) {int c = getState() - releases;if (Thread.currentThread() != getExclusiveOwnerThread())throw new IllegalMonitorStateException();boolean free = false;if (c == 0) {free = true;setExclusiveOwnerThread(null);}setState(c);return free;
}
 
四、AQS 线程状态控制核心机制:LockSupport
AQS 底层通过 LockSupport.park() 和 unpark(thread) 来挂起/唤醒线程:
park():当前线程阻塞,等待被唤醒;unpark(Thread t):唤醒指定线程;- 这种控制机制替代了传统的 
wait/notify,更灵活、底层、性能好。 
五、总结:如何理解 AQS 的强大之处?
| 特性 | 说明 | 
|---|---|
| 模板方法设计 | 只需实现 tryAcquire 和 tryRelease,其他线程队列处理由 AQS 自动完成 | 
| 双模式支持 | 支持共享与独占两种访问模型 | 
| 高可复用性 | 可构建多种同步组件(锁、信号量、栅栏等) | 
| 高性能 | 结合 CAS、自旋、队列挂起唤醒机制 | 
| 阻塞线程管理 | 使用 LockSupport 精细控制线程挂起与恢复 |