AQS 是啥

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

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

一、一句话理解

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) 同一时刻只有一个线程能拿到 ReentrantLock、ReentrantReadWriteLock 写锁
共享模式(Shared) 多个线程可同时拿到 Semaphore、CountDownLatch、读写锁读锁

五、和 synchronized 的区别

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

ReentrantLock 比 synchronized 功能多,就是因为 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 是什么?
  • ReentrantLock 和 synchronized 区别?
  • 公平锁 / 非公平锁怎么实现?

2. 理解并发工具的原理

知道 AQS 后,Semaphore、CountDownLatch 就不再是「黑盒 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 表示资源状态,用队列管理等待线程,子类只定义「怎么抢、怎么放」,其余排队、阻塞、唤醒都由它统一搞定。

相关推荐
AI你一生一世3 小时前
不止于时序存储:DolphinDB 如何成为 AI 时代的工业智能底座
java·人工智能·struts·时序数据库·工业智能·dolphindb·ai基础设施
布莱克6053 小时前
C/C++ 中变量的声明与定义:区别、联系与常见误区
c语言·开发语言·c++·声明·定义
云-缩影3 小时前
拆解 AI 图像生成应用的后端架构:ECS、OSS 和大模型 API 怎么配合
java·spring boot·后端
LabVIEW开发3 小时前
LabVIEW 局部变量为何引发竞争条件?四种同步机制
开发语言·labview
瑞克-桑切斯4 小时前
7、MySQL 慢查询排查与优化实战指南
java·服务器·数据库
benchmark_cc4 小时前
A 股、港股、美股如何建立统一的标的主数据格式?
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
Zenova EdgeOS5 小时前
Go 工业边缘错误处理实战:用 errors 构建可追溯错误链
开发语言·数据库·golang
取名真是5 小时前
Python 算法知识点从基础到进阶
开发语言·python·算法
FRing036 小时前
vue2干货总结3(computed计算属性、watch监听器)
开发语言·前端·vue.js·vue2
Fatbobman(东坡肘子)7 小时前
快速消失的硬盘容量 -- 肘子的 Swift 周报 #160
开发语言·人工智能·redis·ios·swiftui·iphone·swift