AQS机制详解与总结
AQS(AbstractQueuedSynchronizer)机制详解与总结
- 一. AQS(AbstractQueuedSynchronizer)简介
- 1. 核心理念:
- 2. 核心成员变量state:
- 3. 工作机制简述:
- 二、AQS的核心任务
- 三、AQS的核心组成
- 四、CAS 与 AQS 的区别与联系
- 1. CAS(Compare-And-Swap)
- 2. AQS
- 3. 关系总结
- 五、使用 AQS 实现可重入公平锁 实现步骤
一. AQS(AbstractQueuedSynchronizer)简介
AQS 是 Java 并发包中用于构建锁(如 ReentrantLock
)、同步器(如 Semaphore
、CountDownLatch
)和协作工具类的核心框架。
1. 核心理念:
- 独占资源控制: 当共享资源空闲时,线程尝试通过原子操作获得资源,并设置为锁定状态。
- 队列化等待机制: 如果资源被占用,线程将被加入一个基于 FIFO 的虚拟双向队列(CLH队列) 中进行阻塞等待,直到被唤醒再次尝试。
2. 核心成员变量state:
// 表示同步状态的变量
private volatile int state;
state
是 AQS 中用于表示同步状态的关键变量。- 在
ReentrantLock
中,state 表示锁的重入次数; - 在
Semaphore
中,state 表示剩余的许可证数量; - 在
CountDownLatch
中,state 表示倒计时计数。
- 在
- 该变量由
volatile
修饰,确保多线程间的可见性。 - 所有对
state
的修改均通过 CAS(Compare-And-Swap)操作 保证原子性,避免使用重量级的锁。
3. 工作机制简述:
┌───────────────┐
│ 线程A │
└─────┬─────────┘
│ acquire()
▼
┌─────────────────────┐
│ AQS(框架) │
│ ┌───────────────┐ │
│ │ state(volatile)│◄───CAS原子更新
│ └───────────────┘ │
│ ┌───────────────┐ │
│ │ FIFO等待队列 │◄─入队/出队/唤醒线程
│ └───────────────┘ │
└─────────────────────┘
(1)获取锁(Acquire):
- 使用 CAS 尝试修改
state
。 - 成功:表示当前线程获取锁成功,继续执行。
- 失败:进入等待队列(CLH),阻塞当前线程。
(2)释放锁(Release):
- 同样使用 CAS 更新
state
。 - 如果
state
变为允许状态,则唤醒等待队列中的下一个线程。
二、AQS的核心任务
AQS 作为 Java 并发框架中的核心同步器框架,主要负责以下三个方面:
- 同步状态(state)的原子操作
- 通过
volatile
保证可见性,CAS
保证原子性。
- 通过
- 线程的阻塞与唤醒
- 利用内置 FIFO 等待队列(CLH队列)管理线程挂起与恢复。
- 等待队列的管理
- 包括节点的入队、出队、取消、唤醒等机制。
三、AQS的核心组成
组件 | 说明 |
---|---|
state 变量 | 表示同步状态,具体含义由子类定义: 🔸 Semaphore :剩余许可证数量🔸 CountDownLatch :倒计时计数🔸 ReentrantLock :锁状态(含重入次数) |
FIFO 等待队列 | 线程在竞争失败后会进入队列,按照顺序等待资源 |
协作工具类方法 | 如 acquire() 、release() 、await() 、countDown() 等,具体行为由子类重写 tryAcquire() 和 tryRelease() 实现 |
四、CAS 与 AQS 的区别与联系
1. CAS(Compare-And-Swap)
- 一种无锁原子操作机制。
- 依赖于硬件指令实现原子性。
- 三个操作数:V(内存值)、A(期望值)、B(更新值)。
- 如果 V == A,则将 V 更新为 B;否则什么都不做。
2. AQS
- 一套**构建同步器(如锁、信号量)**的抽象框架。
- 内部通过
volatile state
表示状态。 - 使用
CAS
操作来更新state
,保证原子性。 - 通过 CLH 队列管理线程等待。
3. 关系总结
- AQS 依赖 CAS 实现对
state
的原子更新。 - AQS 封装了大量与线程调度、状态管理、阻塞唤醒相关的逻辑,而 CAS 是实现原子性的关键技术手段。
五、使用 AQS 实现可重入公平锁 实现步骤
1. 继承 AbstractQueuedSynchronizer
- 创建一个静态内部类,继承 AQS。
- 重写核心方法:
tryAcquire(int arg)
tryRelease(int arg)
isHeldExclusively()
2. 实现可重入逻辑
- 在
tryAcquire
中判断:- 若当前线程已持有锁,则支持重入(
state++
)。 - 否则尝试通过
CAS
获取锁(state=0 -> 1
)。
- 若当前线程已持有锁,则支持重入(
3. 实现公平性机制
- 在
tryAcquire
中优先检查等待队列:- 若有前驱节点在等待,当前线程需排队,不可直接竞争锁。
4. 封装为外部锁类
- 外部类持有 AQS 子类的实例。
- 提供
lock()
和unlock()
方法,内部调用 AQS 的同步逻辑。