面试资料大全|各种技术资料-2000G
一、AQS 本质与定位
AQS(AbstractQueuedSynchronizer) 是 Java 并发包(java.util.concurrent.locks
)的核心框架,它为实现阻塞锁和同步器提供了底层支持。作为 Java 并发编程的基石,AQS 被广泛应用于 JUC(Java Util Concurrent)中:
classDiagramAbstractQueuedSynchronizer <|-- ReentrantLock$SyncAbstractQueuedSynchronizer <|-- Semaphore$SyncAbstractQueuedSynchronizer <|-- CountDownLatch$SyncAbstractQueuedSynchronizer <|-- ReentrantReadWriteLock$SyncReentrantLock$Sync <|-- NonfairSyncReentrantLock$Sync <|-- FairSync
核心价值:AQS 解决了同步器的排队机制和线程阻塞/唤醒等通用问题,让开发者只需关注状态管理逻辑
二、AQS 核心设计思想
1. 三大核心组件
组件 | 作用 | 实现方式 |
---|---|---|
状态变量 (state) | 同步状态(如锁的重入次数、信号量许可数) | volatile int + CAS 操作 |
CLH 队列 | 存储等待线程的 FIFO 队列 | 双向链表(Node 节点) |
模板方法 | 供子类实现的获取/释放逻辑 | tryAcquire()/tryRelease() 等方法 |
2. CLH 队列原理
节点结构:
static final class Node {volatile int waitStatus; // 等待状态volatile Node prev; // 前驱节点volatile Node next; // 后继节点volatile Thread thread; // 等待线程Node nextWaiter; // 条件队列专用
}
等待状态值:
CANCELLED (1)
:线程已取消SIGNAL (-1)
:后继线程需要被唤醒CONDITION (-2)
:线程在条件队列等待PROPAGATE (-3)
:共享模式下状态需要传播
三、AQS 工作原理
1. 独占模式获取锁(acquire)
public final void acquire(int arg) {if (!tryAcquire(arg) && // 子类实现获取逻辑acquireQueued( // 加入等待队列addWaiter(Node.EXCLUSIVE), arg)) // 创建独占节点selfInterrupt(); // 恢复中断状态
}
2. 节点入队流程
四、AQS 的两种模式
1. 独占模式(Exclusive)
- 特点:同一时刻只有一个线程能获取资源
- 应用:
ReentrantLock
- 核心方法:
protected boolean tryAcquire(int arg) // 子类实现 protected boolean tryRelease(int arg) // 子类实现
2. 共享模式(Shared)
- 特点:多个线程可同时获取资源
- 应用:
Semaphore
,CountDownLatch
- 核心方法:
protected int tryAcquireShared(int arg) // 子类实现 protected boolean tryReleaseShared(int arg) // 子类实现
五、AQS 在同步器中的实现
1. ReentrantLock 实现
// 非公平锁获取
final boolean nonfairTryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (compareAndSetState(0, acquires)) { // CAS抢锁setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) { // 重入逻辑setState(c + acquires);return true;}return false;
}
2. Semaphore 实现
protected int tryAcquireShared(int acquires) {for (;;) {int available = getState();int remaining = available - acquires;if (remaining < 0 || compareAndSetState(available, remaining)) // CAS扣减许可return remaining;}
}
六、AQS 的四大关键技术
1. CAS(Compare-And-Swap)
// 原子更新状态
protected final boolean compareAndSetState(int expect, int update) {return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
2. LockSupport 线程控制
// 阻塞当前线程
LockSupport.park(this);// 唤醒指定线程
LockSupport.unpark(thread);
3. 自旋优化
for (;;) { // 自旋避免直接阻塞if (canAcquire) break;// 短暂自旋后进入阻塞
}
4. 队列管理算法
- 入队:CAS设置尾节点
- 出队:设置头节点并唤醒后继
- 取消:清理CANCELLED节点
七、AQS 的高级特性
1. 条件变量(ConditionObject)
public class ConditionObject implements Condition {public final void await() {Node node = addConditionWaiter(); // 加入条件队列int savedState = fullyRelease(node);while (!isOnSyncQueue(node)) {LockSupport.park(this); // 阻塞}acquireQueued(node, savedState); // 重新竞争锁}
}
2. 公平 vs 非公平策略
策略 | 实现原理 | 优点 | 缺点 |
---|---|---|---|
非公平锁 | 新线程直接 CAS 抢锁 | 高吞吐量 | 可能线程饥饿 |
公平锁 | 检查队列是否有等待线程才尝试获取 | 保证顺序性 | 上下文切换多 |
八、为什么需要 AQS
传统同步的局限性
// synchronized 不足:
// 1. 无法中断等待
// 2. 单一等待队列
// 3. 无法实现复杂策略// wait/notify 不足:
// 1. 必须配合synchronized使用
// 2. 通知是广播式的
AQS 的优势
- 灵活性:支持尝试获取、超时获取、可中断获取
- 扩展性:通过继承实现自定义同步器
- 高性能:CAS + CLH队列减少竞争
- 功能性:支持多个条件变量
九、AQS 的最佳实践
自定义同步器示例
class SimpleLock extends AbstractQueuedSynchronizer {// 尝试获取锁protected boolean tryAcquire(int acquires) {if (compareAndSetState(0, 1)) {setExclusiveOwnerThread(Thread.currentThread());return true;}return false;}// 尝试释放锁protected boolean tryRelease(int releases) {if (getState() == 0) throw new IllegalMonitorStateException();setExclusiveOwnerThread(null);setState(0);return true;}// 创建锁接口public void lock() { acquire(1); }public void unlock() { release(1); }
}
使用注意事项
-
状态管理:
// 正确使用原子操作 compareAndSetState(oldState, newState);// 错误:直接修改状态 setState(newState); // 非线程安全!
-
避免死锁:
lock.lock(); try {// 临界区代码 } finally {lock.unlock(); // 必须确保释放 }
面试资料大全|各种技术资料-2000G