一、AQS概述
AQS是Java并发包中构建锁和同步器的基础框架,通过FIFO队列管理线程的竞争与唤醒,核心思想是将资源访问抽象为状态(state)管理,结合CLH队列实现线程排队。
二、核心方法解析
1. acquireQueued方法
- 功能:管理线程在同步队列中的阻塞与唤醒,循环尝试获取锁。
- 关键逻辑:
- 前驱检查:仅当线程的前驱节点是头节点时尝试获取锁(
tryAcquire)。 - 线程挂起:通过
shouldParkAfterFailedAcquire判断是否需要挂起线程,使用LockSupport.park()实现阻塞。 - 中断处理:记录中断状态但不立即响应,确保锁获取后处理中断。
- 异常处理:在
finally块中调用cancelAcquire清理无效节点。
- 前驱检查:仅当线程的前驱节点是头节点时尝试获取锁(
2. shouldParkAfterFailedAcquire方法
- 功能:判断线程是否应挂起,并维护队列有效性。
- 关键逻辑:
- 状态检查:
- 前驱状态为
SIGNAL(-1):返回true,允许挂起。 - 前驱状态为
CANCELLED(>0):跳过已取消节点,重新链接队列。 - 前驱状态为
0或PROPAGATE:通过CAS将其设为SIGNAL,要求重试锁获取。
- 前驱状态为
- 设计意义:确保线程挂起前最后一次检查锁状态,避免无效阻塞。
- 状态检查:
三、AQS设计思想
1. 模板方法模式
- 不变流程:AQS封装同步队列管理、线程阻塞/唤醒等通用逻辑(如
acquire和release)。 - 可变扩展:子类实现
tryAcquire、tryRelease等抽象方法定义具体锁策略(如公平锁/非公平锁)。
2. 高效并发控制
- 无锁化操作:通过CAS(如
compareAndSetWaitStatus)更新节点状态,减少锁竞争。 - 状态驱动:依赖
waitStatus实现链式唤醒,前驱节点释放锁时触发后继节点唤醒。
3. 健壮性保障
- 队列自愈:自动清理
CANCELLED节点,维护双向链表的有效性。 - 中断协作:延迟中断响应(通过
interrupted标志),避免锁获取过程中断丢失。
四、假性唤醒处理
- 问题场景:线程可能未收到
signal()/unpark()就被唤醒。 - 防御机制:
- 循环检查条件:所有
await()/park()调用必须包裹在while循环中。 - 状态重验证:唤醒后重新检查前驱节点状态和锁条件(见
acquireQueued的for (;;)循环)。
- 循环检查条件:所有
五、关键代码段示例
acquireQueued核心逻辑
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) { // 仅头节点后继可竞争锁
setHead(node); // 更新头节点
p.next = null; // 断开原头节点引用
return interrupted; // 返回中断状态
}
if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) {
interrupted = true; // 记录中断但不立即响应
}
}
shouldParkAfterFailedAcquire状态处理
if (pred.waitStatus == Node.SIGNAL) {
return true; // 允许挂起
} else if (pred.waitStatus > 0) {
// 跳过已取消的前驱节点,修复队列
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
// CAS设置前驱状态为SIGNAL,要求重试锁获取
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
六、应用场景
- 锁实现:如
ReentrantLock、ReentrantReadWriteLock。 - 同步器:如
Semaphore、CountDownLatch、CyclicBarrier。 - 线程池:用于
ThreadPoolExecutor的工作线程管理。
七、最佳实践
- 避免直接调用AQS方法:优先使用
java.util.concurrent包中的高层同步工具。 - 自定义同步器:继承AQS时,仅需重写
tryAcquire/tryRelease等方法。 - 性能优化:
- 非公平锁减少线程切换开销。
- 减少锁粒度,结合
Condition实现精细等待/通知。
170万+

被折叠的 条评论
为什么被折叠?



