Java并发-AQS框架原理解析与实现类详解
什么是AQS?
AQS(AbstractQueuedSynchronizer)是Java并发包(JUC)的核心基础框架,它为构建锁和同步器提供了高效、灵活的底层支持。本文将从设计原理、核心机制及典型实现类三个维度展开,帮助读者全面掌握AQS的运作机制与应用场景。
一、AQS的核心原理
1. 同步状态管理
AQS通过一个volatile int
类型的变量state
表示同步状态,并提供以下原子操作方法:
- getState():获取当前状态值。
- setState(int):直接设置状态值。
- compareAndSetState(int, int):通过CAS(比较并交换)原子更新状态。
例如,在ReentrantLock
中,state=0
表示未加锁,state>0
表示锁被占用且记录重入次数;在Semaphore
中,state
表示可用许可证数量。
2. CLH队列与线程调度
AQS基于CLH(Craig, Landin, Hagersten)锁队列的变种实现线程阻塞与唤醒机制:
- 队列结构:内部维护一个FIFO双向链表,每个节点(Node)封装一个等待线程,包含
prev
和next
指针,以及waitStatus
状态(如SIGNAL
表示需唤醒后继节点)。 - 阻塞与唤醒:线程获取资源失败时,通过
LockSupport.park()
阻塞;资源释放时,通过LockSupport.unpark()
唤醒队列中的下一个线程。
3. 两种资源共享模式
- 独占模式(Exclusive):同一时间仅允许一个线程持有资源(如
ReentrantLock
)。 - 共享模式(Shared):允许多个线程同时访问资源(如
Semaphore
、CountDownLatch
)。
二、AQS的关键组件与设计模式
1. 模板方法模式
AQS通过模板方法定义同步器的核心逻辑,子类需重写以下方法:
- tryAcquire(int):尝试独占获取资源。
- tryRelease(int):尝试独占释放资源。
- tryAcquireShared(int):尝试共享获取资源。
- tryReleaseShared(int):尝试共享释放资源。
例如,ReentrantLock
的Sync
类通过重写tryAcquire
实现可重入锁的逻辑。
2. 公平性与非公平性
- 公平锁:按线程入队顺序分配资源,通过
hasQueuedPredecessors()
检查是否有前驱节点。 - 非公平锁:允许新请求的线程“插队”直接尝试获取资源,提高吞吐量但可能导致饥饿。
三、AQS的典型实现类
1. 独占锁:ReentrantLock
- 特点:支持可重入,同一线程可多次获取锁(
state
累加),需等释放次数与获取次数匹配后彻底释放。 - 公平性控制:通过构造函数选择公平或非公平策略。
2. 共享锁:Semaphore
- 功能:控制同时访问资源的线程数。
state
表示可用许可证数量,acquire()
减少许可证,release()
增加许可证。
3. 闭锁:CountDownLatch
- 机制:初始化
state=N
,每个线程执行完成后调用countDown()
(state
减1),当state=0
时唤醒所有等待线程(如主线程)。
4. 读写锁:ReentrantReadWriteLock
- 分离设计:读锁(共享)允许多线程并发读,写锁(独占)互斥写操作,提升高并发场景性能。
5. 循环屏障:CyclicBarrier
- 用途:多线程在屏障点等待,直到所有线程到达后继续执行。AQS管理线程队列,并在条件满足时统一唤醒。
四、AQS与内置锁的对比
特性 | 内置锁(synchronized) | AQS显式锁(如ReentrantLock) |
---|---|---|
中断支持 | 不可中断 | 支持lockInterruptibly() |
尝试获取锁 | 不支持 | 支持tryLock() |
公平性 | 仅非公平 | 可配置公平或非公平 |
条件变量 | 单一条件队列 | 支持多个Condition 对象 |
锁释放 | 自动释放 | 需手动在finally 中释放 |
(参考)
五、总结与最佳实践
AQS通过状态管理、队列调度和模板方法,为Java并发工具提供了高效的基础设施。实际开发中的选择建议:
- 若无特殊需求(如可中断、公平性),优先使用内置锁(JDK6后性能优化显著)。
- 需要高级功能(如超时、条件变量)时,选择基于AQS的显式锁。
示例代码(自定义同步器):
class CustomSync extends AbstractQueuedSynchronizer {@Overrideprotected boolean tryAcquire(int arg) {return compareAndSetState(0, 1); // 独占模式,CAS获取锁}@Overrideprotected boolean tryRelease(int arg) {setState(0); // 释放锁return true;}
}