Java AQS(AbstractQueuedSynchronizer)详解
Java AQS(AbstractQueuedSynchronizer)详解
AQS(AbstractQueuedSynchronizer) 是 Java 并发包(java.util.concurrent.locks
)的核心基础框架,用于构建锁和其他同步器。ReentrantLock、Semaphore、CountDownLatch 等同步工具均基于 AQS 实现。
一、核心设计思想
-
状态管理
通过volatile int state
表示同步状态(如锁的重入次数、信号量的许可数)。private volatile int state; // 关键状态变量
提供原子操作修改状态:
protected final boolean compareAndSetState(int expect, int update) {// CAS 操作更新 state }
-
等待队列(CLH 变体)
- 双向链表(FIFO)管理阻塞线程。
- 节点类型:
- EXCLUSIVE(独占模式,如 ReentrantLock)
- SHARED(共享模式,如 Semaphore)
二、核心结构
// 队列节点定义
static final class Node {volatile int waitStatus; // 节点状态(CANCELLED、SIGNAL、CONDITION等)volatile Node prev; // 前驱节点volatile Node next; // 后继节点volatile Thread thread; // 关联的线程Node nextWaiter; // 条件队列或共享模式标记
}
等待状态值:
CANCELLED (1)
:线程已取消SIGNAL (-1)
:后继节点需被唤醒CONDITION (-2)
:线程在条件队列中等待PROPAGATE (-3)
:共享模式下传播唤醒
三、工作模式
-
独占模式(Exclusive)
-
加锁流程:
public final void acquire(int arg) {if (!tryAcquire(arg) && // 子类实现尝试获取锁acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // 加入队列并阻塞selfInterrupt(); }
tryAcquire()
:由子类实现(如 ReentrantLock 中判断重入)addWaiter()
:将线程包装为节点加入队尾acquireQueued()
:自旋或阻塞等待唤醒
-
解锁流程:
public final boolean release(int arg) {if (tryRelease(arg)) { // 子类实现释放锁Node h = head;if (h != null && h.waitStatus != 0)unparkSuccessor(h); // 唤醒后继节点return true;}return false; }
-
-
共享模式(Shared)
- 用于信号量、CountDownLatch 等。
- 核心方法:
acquireShared()
/releaseShared()
- 与独占模式区别:唤醒时传播唤醒后续共享节点(如
PROPAGATE
状态)。
四、关键模板方法
子类必须实现的方法:
方法 | 作用 |
---|---|
boolean tryAcquire(int) | 独占模式获取锁 |
boolean tryRelease(int) | 独占模式释放锁 |
int tryAcquireShared(int) | 共享模式获取锁(返回剩余许可数) |
boolean tryReleaseShared(int) | 共享模式释放锁 |
boolean isHeldExclusively() | 当前线程是否独占资源 |
五、自定义锁示例(不可重入锁)
public class SimpleLock extends AbstractQueuedSynchronizer {@Overrideprotected boolean tryAcquire(int arg) {if (compareAndSetState(0, 1)) { // CAS 修改 state: 0->1setExclusiveOwnerThread(Thread.currentThread()); // 设置独占线程return true;}return false;}@Overrideprotected boolean tryRelease(int arg) {if (getState() == 0) throw new IllegalMonitorStateException();setExclusiveOwnerThread(null); // 清除独占线程setState(0); // 状态重置为0return true;}public void lock() {acquire(1); // 调用AQS的独占获取}public void unlock() {release(1); // 调用AQS的独占释放}
}
六、AQS 在 JUC 中的应用
同步器 | 实现原理 |
---|---|
ReentrantLock | 独占模式 + state 记录重入次数 |
Semaphore | 共享模式 + state 表示许可数 |
CountDownLatch | 共享模式 + state 表示计数 |
ReentrantReadWriteLock | 读锁共享 + 写锁独占 |
七、高级特性
-
条件变量(Condition)
- 通过
ConditionObject
实现(内部维护条件队列)。 await()
:释放锁并进入条件队列。signal()
:将节点从条件队列移到同步队列。
- 通过
-
中断处理
acquireInterruptibly()
:支持响应中断的获取锁。
八、总结
- 核心价值:提供统一的线程排队、阻塞/唤醒机制。
- 关键优势:子类只需关注状态管理逻辑(
tryAcquire
/tryRelease
)。 - 适用场景:构建高性能、可扩展的同步器。
提示:理解 AQS 是掌握 Java 并发编程的关键!建议结合源码(如
ReentrantLock
)深入分析队列操作和状态转换。