如何理解 AQS ?
AQS(AbstractQueuedSynchronizer) 是 Java 并发包(java.util.concurrent
)的核心基础框架,用于构建锁和其他同步器(如 ReentrantLock
、Semaphore
、CountDownLatch
等)。它通过 FIFO 队列 管理线程的排队与唤醒,并基于 模板方法模式 提供了同步状态的管理机制,开发者只需实现特定方法即可自定义同步器。
AQS 的核心思想
AQS 的核心是 通过一个共享的原子状态(state
)和一个双向 CLH 队列(线程等待队列),实现多线程对共享资源的竞争与协调:
- 状态管理:通过
volatile int state
表示资源是否可用(如锁是否被持有)。 - 线程排队:未获取资源的线程会被封装为
Node
对象,加入 CLH 队列等待。 - 模板方法:AQS 定义关键模板方法(如
tryAcquire
、tryRelease
),具体逻辑由子类实现。
同步状态(state
)
- 一个
volatile
修饰的整型变量,表示资源的状态。 - 示例:
ReentrantLock
:state=0
表示锁未被占用,state=N
表示被重入 N 次。Semaphore
:state
表示剩余可用许可证数量。
CLH 队列(线程等待队列)
- 一个 双向链表 结构的线程等待队列,用于管理未获取资源的线程。
- 每个线程被封装为
Node
节点,包含前驱(prev
)、后继(next
)和线程引用。 - 特点:公平锁基于 CLH 队列实现先进先出的竞争策略。
为什么需要 AQS ?
简单来说 AQS 就是起到了一个抽象、封装的作用,将一些排队、入队、加锁、中断等方法提供出来,便于其他相关 JUC 锁的使用,具体加锁时机、入队时机等都需要实现类自己控制。
它主要通过维护一个共享状态(state) 和一个 先进先出(FIFO)的等待队列,来管理线程对共享资源的访问。
state 用 volatile 修饰,表示当前资源的状态。例如,在独占锁中,state 为 0 表示未被占用,为 1 表示已被占用。
当线程尝试获取资源失败时,会被加入到 AQS 的等待队列中。这个队列是一个变体的 CLH 队列,采用双向链表结构,节点包含线程的引用、等待状态以及前驱和后继节点的指针。
AQS常见的实现类有 ReentrantLock
、CountDownLatch
、Semaphore
等等。