Skip to content

AQS

从ReentrantLock的实现看AQS的原理及应用

AQS是一种提供了原子式管理同步状态阻塞和唤醒线程功能以及队列模型的简单框架。

组成

  1. 共享资源状态维护state。

    • AQS使用一个volatile修饰的 int 成员变量来表示同步状态,这个状态可以反映锁的当前持有情况。

      例如,当状态为 0 时表示无锁状态,而当状态为非零时表示有锁被占用。

  2. FIFO 队列实现线程排队

    AQS维护了一个FIFO(先入先出)的双向队列,用于管理等待获取锁的线程,当一个线程尝试获取锁但失败时,它会进入这个队列并阻塞,直到锁被释放。

    image-20250528172108770

  3. CAS操作实现同步状态修改

    AQS使用 compareAndSetState 方法进行原子操作来修改同步状态,这个方法通过循环CAS操作来确保对状态变量的更新,如果更新成功,则表示操作成功,否则会重新尝试。

    AQS使用一个Volatile的int类型的成员变量来表示同步状态,通过内置的FIFO队列来完成资源获取的排队工作,通过CAS完成对State值的修改。

AQS应用

  1. 独占锁和共享锁模式

    AQS支持独占锁和共享锁两种模式,独占锁模式下,每次只有一个线程可以获取锁,而共享锁模式下,允许多个线程同时获取锁。

  2. 条件队列和信号量

    AQS还支持条件队列和信号量等同步机制,这些机制允许线程在等待某些条件(如锁被释放)时阻塞,并在满足条件时被唤醒

JUC中的应用场景

除了上边 ReentrantLock 的可重入性的应用,AQS 作为并发编程的框架,为很多其他同步工具提供了良好的解决方案。下面列出了JUC中的几种同步工具,大体介绍一下AQS的应用场景:

同步工具同步工具与AQS的关联
ReentrantLock使用AQS保存锁重复持有的次数。当一个线程获取锁时,ReentrantLock记录当前获得锁的线程标识,用于检测是否重复获取,以及错误线程试图解锁操作时异常情况的处理。
Semaphore使用AQS同步状态来保存信号量的当前计数。tryRelease会增加计数,acquireShared会减少计数。
CountDownLatch使用AQS同步状态来表示计数。计数为0时,所有的Acquire操作(CountDownLatch的await方法)才可以通过。
ReentrantReadWriteLock使用AQS同步状态中的16位保存写锁持有的次数,剩下的16位用于保存读锁的持有次数。
ThreadPoolExecutorWorker利用AQS同步状态实现对独占线程变量的设置(tryAcquire和tryRelease)。

自定义同步器在实现时只需要实现共享资源 state 的获取与释放方式即可,至于具体线程等待队列的维护(如获取资源失败入队/唤醒出队等),AQS已经在顶层实现好了。