Java中的**AQS(AbstractQueuedSynchronizer)**是并发包java.util.concurrent
的核心组件,用于构建锁和同步器的基础框架。许多并发工具(如ReentrantLock、Semaphore、CountDownLatch等)都基于AQS实现。
AQS 核心原理
- 状态管理(State)
通过volatile int state
变量表示共享资源的状态(如锁的持有计数、信号量的许可数),通过CAS(Compare-And-Swap)操作保证原子性修改。 - CLH队列(线程阻塞队列)
使用一个FIFO双向队列(CLH锁的变体)管理等待线程。当线程获取资源失败时,会被封装为Node
节点加入队列,通过自旋或阻塞等待唤醒。 - 两种模式
- 独占模式(Exclusive):资源仅由一个线程持有(如ReentrantLock)。
- 共享模式(Shared):资源可被多个线程共享(如Semaphore)。
关键方法
子类需重写以下方法(模板方法模式):
- 独占模式
tryAcquire(int arg)
:尝试获取资源。
tryRelease(int arg)
:尝试释放资源。 - 共享模式
tryAcquireShared(int arg)
:尝试获取共享资源。
tryReleaseShared(int arg)
:尝试释放共享资源。
AQS提供acquire()
、release()
等模板方法,内部调用上述子类方法,并处理线程排队与唤醒。
AQS 应用示例
以非重入锁为例:
public class NonReentrantLock implements Lock {
private static class Sync extends AbstractQueuedSynchronizer {
@Override
protected boolean tryAcquire(int arg) {
if (compareAndSetState(0, 1)) { // CAS尝试获取锁
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
@Override
protected boolean tryRelease(int arg) {
if (getState() == 0) throw new IllegalMonitorStateException();
setExclusiveOwnerThread(null);
setState(0); // 释放锁
return true;
}
}
private final Sync sync = new Sync();
@Override
public void lock() {
sync.acquire(1);
}
@Override
public void unlock() {
sync.release(1);
}
// 其他方法省略...
}
AQS 节点状态
- CANCELLED (1):线程因超时或中断放弃等待。
- SIGNAL (-1):当前节点释放资源后需唤醒后继节点。
- CONDITION (-2):节点在条件队列中等待。
- PROPAGATE (-3):共享模式下唤醒需传播给后续节点。
优势与场景
- 灵活性:通过重写少量方法即可实现自定义同步器。
- 高效性:基于CAS和CLH队列减少竞争开销。
- 广泛应用:Java并发工具的核心基础。
学习AQS的意义:理解其原理是掌握Java并发编程的关键,尤其在高性能锁设计、线程调度优化等场景中至关重要。