如何理解 AQS ?

AQS(AbstractQueuedSynchronizer) 是 Java 并发包(java.util.concurrent)的核心基础框架,用于构建锁和其他同步器(如 ReentrantLockSemaphoreCountDownLatch 等)。它通过 FIFO 队列 管理线程的排队与唤醒,并基于 模板方法模式 提供了同步状态的管理机制,开发者只需实现特定方法即可自定义同步器。

AQS 的核心思想

AQS 的核心是 通过一个共享的原子状态(state)和一个双向 CLH 队列(线程等待队列),实现多线程对共享资源的竞争与协调:

  1. 状态管理:通过 volatile int state 表示资源是否可用(如锁是否被持有)。
  2. 线程排队:未获取资源的线程会被封装为 Node 对象,加入 CLH 队列等待。
  3. 模板方法:AQS 定义关键模板方法(如 tryAcquiretryRelease),具体逻辑由子类实现。

同步状态(state

  • 一个 volatile 修饰的整型变量,表示资源的状态。
  • 示例
    • ReentrantLockstate=0 表示锁未被占用,state=N 表示被重入 N 次。
    • Semaphorestate 表示剩余可用许可证数量。

CLH 队列(线程等待队列)

  • 一个 双向链表 结构的线程等待队列,用于管理未获取资源的线程。
  • 每个线程被封装为 Node 节点,包含前驱(prev)、后继(next)和线程引用。
  • 特点:公平锁基于 CLH 队列实现先进先出的竞争策略。

为什么需要 AQS ?

简单来说 AQS 就是起到了一个抽象、封装的作用,将一些排队、入队、加锁、中断等方法提供出来,便于其他相关 JUC 锁的使用,具体加锁时机、入队时机等都需要实现类自己控制。

它主要通过维护一个共享状态(state) 和一个 先进先出(FIFO)的等待队列,来管理线程对共享资源的访问。

state 用 volatile 修饰,表示当前资源的状态。例如,在独占锁中,state 为 0 表示未被占用,为 1 表示已被占用。

当线程尝试获取资源失败时,会被加入到 AQS 的等待队列中。这个队列是一个变体的 CLH 队列,采用双向链表结构,节点包含线程的引用、等待状态以及前驱和后继节点的指针。

AQS常见的实现类有 ReentrantLockCountDownLatchSemaphore 等等。