【深入解析——AQS源码】

深入解析 AQS 源码

一、前言

在 Java 并发编程的世界里,AbstractQueuedSynchronizer(简称 AQS )是 JUC 包的核心基础组件。常见的同步工具类,例如 ReentrantLockSemaphoreCountDownLatchFutureTask 等,底层都依赖 AQS 来实现。理解 AQS 的设计和源码,可以帮助我们透彻掌握 Java 并发工具的原理。


二、AQS 的核心思想

AQS 的核心是 同步状态 + 队列管理

  1. state 变量 :通过一个 volatile int state 表示同步状态(例如锁是否被占用,剩余许可证数量等)。
  2. FIFO 队列:使用一个变种的 CLH 双向队列来管理等待的线程。
  3. 模板方法模式:获取/释放锁的通用逻辑由 AQS 实现,具体的 tryAcquire/tryRelease 逻辑交由子类实现。

三、源码核心结构

1. state 的操作

AQS 提供了对同步状态的安全操作:

java 复制代码
protected final int getState() { return state; }
protected final void setState(int newState) { state = newState; }
protected final boolean compareAndSetState(int expect, int update) {
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

这里通过 CAS 保证并发下的原子操作。


2. 独占模式与共享模式

AQS 同时支持两种抽象方法模式:

  • 独占模式 :典型代表 ReentrantLock

    • acquire(int arg) / tryAcquire(int arg):定义模板方法,由子类实现,其他也是
    • release(int arg) / tryRelease(int arg):定义模板方法,由子类实现,其他也是
  • 共享模式 :典型代表 SemaphoreCountDownLatch

    • acquireShared(int arg) / tryAcquireShared(int arg)
    • releaseShared(int arg) / tryReleaseShared(int arg)

3. acquire 的核心流程(独占模式)

java 复制代码
public final void acquire(int arg) {
    if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

执行流程:

  1. tryAcquire:尝试获取锁,子类实现。
  2. 如果失败,addWaiter 将线程加入等待队列。
  3. acquireQueued:在队列中自旋阻塞,直到前驱节点释放资源。

4. Node 节点(CLH 队列)

队列中的线程由 Node 表示:

java 复制代码
static final class Node {
    static final Node SHARED = new Node();
    static final Node EXCLUSIVE = null;

    volatile int waitStatus;
    volatile Node prev;
    volatile Node next;
    volatile Thread thread;
}
  • waitStatus 标识节点状态(如 SIGNAL、CANCELLED)。
  • 通过 prev/next 链接形成双向队列。

四、典型应用

1. ReentrantLock(独占模式)

java 复制代码
static final class NonfairSync extends Sync {
    final void lock() {
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }

    protected final boolean tryAcquire(int acquires) {
        // 可重入逻辑
    }
}

ReentrantLock 通过重写 tryAcquire 来定义获取锁的逻辑,其他排队/阻塞流程交由 AQS 完成。


2. CountDownLatch(共享模式)

java 复制代码
protected int tryAcquireShared(int acquires) {
    return (getState() == 0) ? 1 : -1;
}

protected boolean tryReleaseShared(int releases) {
    for (;;) {
        int c = getState();
        if (c == 0) return false;
        int nextc = c - 1;
        if (compareAndSetState(c, nextc))
            return nextc == 0;
    }
}
  • await() 依赖 acquireShared,当 state=0 时继续执行。
  • countDown() 调用 releaseShared,逐步减少计数,直到为 0 时唤醒所有等待线程。

五、总结

  • AQS 核心state 表示同步状态,CLH 队列管理线程,模板方法模式解耦逻辑。
  • 独占/共享模式:灵活支持多种并发工具。
  • 典型实现ReentrantLockSemaphoreCountDownLatch 等。
  • 模板方法:AQS只是定义对应的tryrelease、tryAcquire等try-xxx抽象方法,对应的方法都是由对应的实现类来实现,并且不强制子类去实现,但是使用时候必须重写,否则报错。

AQS 的设计极其优雅,它把"排队 + 阻塞 + 唤醒 + 状态管理"抽象了出来,真正实现了并发工具类的可复用性。理解 AQS,等于掌握了 JUC 的灵魂。