AQS 是啥

AQS 在 Java 并发里,通常指 AbstractQueuedSynchronizer(抽象队列同步器)。

它是 JUC(java.util.concurrent)里很多锁和同步工具的底层框架。ReentrantLockSemaphoreCountDownLatchReentrantReadWriteLock 等都基于它实现。

一、一句话理解

AQS = 用「一个状态变量 + 一个等待队列」管理线程抢资源、排队、唤醒的通用模板。

你可以把它想成:银行叫号系统

state → 当前还有几个窗口/名额(比如锁是否被占用)

CLH 队列 → 没抢到的人排队

park/unpark → 叫到号唤醒你


二、核心组成

1. state(状态)

一个 volatile int,表示同步状态,含义由子类定义:

工具 state 含义
ReentrantLock 0=未锁,>0=被锁(可重入次数)
Semaphore 剩余许可数
CountDownLatch 还剩几个线程没完成
ReentrantReadWriteLock 高 16 位=读锁数,低 16 位=写锁数

2. CLH 双向队列

抢不到的线程会封装成 Node 放进 FIFO 队列里等待,避免大量线程空转(忙等)。

3. 模板方法

子类只需实现两个方法:

复制代码
// 尝试获取资源(抢锁/抢许可)
protected boolean tryAcquire(int arg)
// 尝试释放资源(放锁/还许可)
protected boolean tryRelease(int arg)

AQS 负责通用的排队、阻塞、唤醒逻辑。


三、工作流程(以独占锁为例)

获取锁(简化理解)

复制代码
public final void acquire(int arg) {
    // 1. 先试着抢
    if (!tryAcquire(arg)) {
        // 2. 抢不到就入队
        // 3. 自旋检查前驱是否是队头
        // 4. 还不行就 park 挂起
    }
}

释放锁

复制代码
public final boolean release(int arg) {
    if (tryRelease(arg)) {
        // 唤醒队列里下一个等待线程
        unparkSuccessor(head);
        return true;
    }
    return false;
}

四、两种模式

模式 说明 典型实现
独占模式(Exclusive) 同一时刻只有一个线程能拿到 ReentrantLockReentrantReadWriteLock 写锁
共享模式(Shared) 多个线程可同时拿到 SemaphoreCountDownLatch、读写锁读锁

五、和 synchronized 的区别

synchronized 基于 AQS 的锁(如 ReentrantLock
实现 JVM 内置,监视器锁 Java 代码实现
灵活性 自动加锁解锁 tryLock、可中断、可超时、可公平
队列 依赖 JVM 实现 明确的 CLH 队列
条件变量 只有一个 wait/notify 可有多个 Condition

ReentrantLocksynchronized 功能多,就是因为 AQS 提供了可扩展的模板。


六、代码里长什么样

ReentrantLock 内部有个继承 AQS 的同步器:

复制代码
// 简化示意,帮助理解
class Sync extends AbstractQueuedSynchronizer {
    protected boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            // 没人占锁,CAS 抢
            if (compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        } else if (current == getExclusiveOwnerThread()) {
            // 重入:同一线程再加锁
            setState(c + acquires);
            return true;
        }
        return false;
    }
    protected boolean tryRelease(int releases) {
        // 释放锁,state 减到 0 时真正放开
        ...
    }
}

业务代码只管 lock() / unlock(),排队和唤醒由 AQS 统一处理。


七、为什么重要

1. 面试常考

  • AQS 是什么?
  • ReentrantLocksynchronized 区别?
  • 公平锁 / 非公平锁怎么实现?

2. 理解并发工具的原理

知道 AQS 后,SemaphoreCountDownLatch 就不再是「黑盒 API」。

3. 和项目的关系

场景 可能用到
接口限流 Semaphore
等待多个任务完成 CountDownLatch
需要可中断/超时加锁 ReentrantLock
线程池 底层也依赖 AQS 协调

你们前面聊的数据库锁、分布式锁、事务,解决的是数据层并发;AQS 解决的是单机 JVM 内线程同步,层次不同,但都服务于「多线程不打架」。


八、常见考点速记

AQS 三件套:

state → 同步状态

CLH 队列 → 等待线程排队

CAS + park → 抢资源 / 阻塞 / 唤醒

子类实现:

tryAcquire → 怎么抢

tryRelease → 怎么放

基于 AQS 的工具:

ReentrantLock

ReentrantReadWriteLock

Semaphore

CountDownLatch

CyclicBarrier(内部也用 ReentrantLock + Condition)


九、一句话总结

AQS 是 Java 并发包的「发动机」:用 state 表示资源状态,用队列管理等待线程,子类只定义「怎么抢、怎么放」,其余排队、阻塞、唤醒都由它统一搞定。

相关推荐
恋恋西风2 小时前
C++ 理解 std::thread 在单核和多核上的行为差异
开发语言·c++
学长毕业设计2 小时前
基于SpringBoot的公益基金管理系统(源码+文档+讲解视频)
java·spring boot·后端
Brilliantwxx2 小时前
【Linux】 进程(9)程序与进程地址空间(基础+进阶+面试题)
linux·运维·服务器·开发语言·c++
东小西2 小时前
【SAA实战】第 3 篇 · 工具调用全攻略:把业务能力交给 Agent 自己调度
java·后端·spring
东小西2 小时前
【SAA实战】第 4 篇 · Agent 短期记忆:saver 让 Agent 跨轮记得住(threadId 隔离)
java·后端·spring
许彰午3 小时前
22-DataCenter报文序列化
java·低代码·架构·状态模式
2601_962065253 小时前
[MySQL] SQL优化之性能分析
java·sql·mysql
BizzZ_3 小时前
C++(22)——类型转换和IO流
开发语言·c++
小范同学_3 小时前
JDK1.7 与 JDK1.8 HashMap 底层原理对比 + 数组并发扩容死循环详解
java·开发语言
geovindu4 小时前
CSharp: 万年历
开发语言·后端·c#·.net