Skip to content

概念卡片:AQS 同步器框架

一句话机制

AQS(AbstractQueuedSynchronizer,抽象队列同步器)是 JUC 的「同步器模板」,用「state 状态变量 + FIFO 等待队列 + CAS 修改 + LockSupport park/unpark」四件套,把「抢锁、排队、阻塞、唤醒」的通用逻辑抽出来,让 ReentrantLock/Semaphore/CountDownLatch 只定义各自的资源语义。 它不是具体的锁,而是构建锁和同步工具的基础模板。

核心组成

AQS = state 状态变量 + FIFO 等待队列 + CAS 修改 + park/unpark 阻塞唤醒
组成作用细节
volatile int state同步状态含义由具体同步器定义(见下)
FIFO 队列管理抢不到资源的线程线程包装成 Node 节点,head <-> node1 <-> ... <-> tail
CAS保证 state 修改原子抢锁时只有一个线程能把 state 0→1
LockSupport阻塞/唤醒park() 挂起、unpark(thread) 唤醒

state 在不同组件的含义

组件state 含义
ReentrantLock锁占用(0=空闲,>0=占用且数值=重入次数)
CountDownLatch计数器(countDown() 减 1,归 0 唤醒等待线程)
Semaphore许可证数量(acquire() 减、release() 加)

两种模式 + 模板方法

独占模式:同一时刻只有一个线程获资源(ReentrantLock)。 共享模式:多个线程同时获资源(Semaphore、CountDownLatch、读写锁的读锁)。

AQS 用模板方法思想:通用流程(入队/阻塞/唤醒/维护队列)由 AQS 实现,具体同步器只需实现资源语义:

java
protected boolean tryAcquire(int arg);        // 独占获取
protected boolean tryRelease(int arg);        // 独占释放
protected int tryAcquireShared(int arg);      // 共享获取(≥0 成功)
protected boolean tryReleaseShared(int arg);  // 共享释放

执行流程(CAS + 队列 + 阻塞唤醒)

1. CAS 尝试快速获取资源
2. 失败 → 线程包装成 Node 入队
3. 必要时 park() 阻塞线程(不空转耗 CPU)
4. 资源释放 → unpark() 唤醒后继节点再试

不是单纯自旋、也不是单纯阻塞,而是「先 CAS 抢一次 → 抢不到就排队阻塞 → 释放后唤醒」的组合,兼顾了低竞争下的快和高竞争下的省。

公平锁 vs 非公平锁(AQS 排队机制)

new ReentrantLock(false) 默认非公平,new ReentrantLock(true) 公平。

  • 非公平锁:新线程来了若锁恰好空闲,可直接抢,不排队 → 吞吐高,但队列线程可能饥饿
  • 公平锁:先检查队列是否有人排队,有人就进队尾 → 公平,但吞吐低

常见误解(避坑)

  1. ❌ "AQS 是一个具体的锁"。→ 它是框架/模板,ReentrantLock/Semaphore/CountDownLatch/ReentrantReadWriteLock 都建立在其上。
  2. ❌ "AQS 全靠 CAS 自旋"。→ 它是「CAS 抢一次 + 失败入队阻塞 + 释放唤醒」,不是纯自旋(纯自旋会耗 CPU)。
  3. ❌ "所有同步工具都用独占模式"。→ 还有共享模式(Semaphore/CountDownLatch/读锁),资源释放后可连续唤醒多个等待线程。
  4. ❌ "state 的值是固定的含义"。→ state 只是一个 int,含义由具体同步器定义(锁占用数/计数器/许可证数),AQS 本身不关心它代表什么。

关联

最近更新