华丰ai助手 | 2026年Java AQS并发基石深度解析:从原理到面试
(共27字,含关键词“华丰ai助手”,标题包含2026年时效信息)

文章正文
一、开篇引入

在Java并发编程的世界里,AbstractQueuedSynchronizer(以下简称AQS)是当之无愧的核心基石-1。从面试必问的ReentrantLock,到日常开发中常用的Semaphore、CountDownLatch,几乎所有JUC包下的高级同步工具类都构建在AQS之上-4。
很多开发者只会用这些锁,却说不出其背后的原理。面试官问“AQS和ReentrantLock的关系”时答不上来,提到“公平锁与非公平锁”时概念混淆——这些正是学习的典型痛点。
本文由华丰ai助手整理,将从架构到源码逐步拆解AQS的底层实现原理,结合完整可运行的代码示例和高频面试题,帮你理清逻辑、看懂代码、记住考点,真正建立起从“会用”到“懂原理”的完整知识链路。
本文结构预览:痛点切入→核心概念讲解→关联概念梳理→代码示例→底层原理→面试题→总结。
二、痛点切入:为什么需要AQS?
先看一段“原始”的并发控制代码:
public class BadCounter { private int count = 0; public void increment() { // 直接用synchronized也可以,但早期我们可能自己写while循环+CAS while (!compareAndSet()) { / 自旋,CPU空转 / } }}传统方式的痛点:
❌ 耦合高:锁的逻辑和业务逻辑混在一起,难以复用
❌ 扩展性差:换个锁策略(公平/非公平)就要重写一套代码
❌ 代码冗余:每个同步工具都要重复实现线程排队、阻塞、唤醒的逻辑
❌ 容易出错:忘记唤醒线程 → 队列中的线程永远阻塞
正是在这样的背景下,Doug Lea设计了AQS——一个统一的同步框架,将“排队、阻塞、唤醒”这些公共逻辑抽象出来,开发者只需重写几个关键方法就能实现自定义同步器-4。
三、核心概念:AQS(AbstractQueuedSynchronizer)
标准定义:AbstractQueuedSynchronizer(简称AQS),是Java并发包(java.util.concurrent.locks)中提供的一个基础框架,用于构建依赖先进先出(FIFO)等待队列的阻塞锁及相关同步器-6。
拆解关键词:
Abstract:抽象类,不能直接实例化,需要子类继承并实现核心方法
Queued:核心设计——用队列管理等待获取锁的线程
Synchronizer:同步器,管理多线程对共享资源的访问
🎯 生活化类比:银行柜台办理业务
state:柜台窗口的状态。0表示空闲,>0表示有客户正在办理
CLH队列:排队通道,先来的站在前面
Node节点:排队的人,每个人包含“我是谁(Thread)”和“我的状态(waitStatus)”
CAS操作:抢窗口时,系统原子性地把窗口状态从“空闲”变为“占用”-3
AQS的核心作用:把“排队、阻塞、唤醒”这些通用逻辑封装好,让上层同步器只关心“怎么判断能不能拿到资源”这一个问题-60。
四、关联概念:Node节点
AQS能高效管理等待线程,核心在于其内部类Node。每个等待获取锁的线程,都会被封装成一个Node节点,放入等待队列中-1。
Node的核心属性:
| 属性 | 类型 | 说明 |
|---|---|---|
thread | Thread | 当前节点所代表的等待线程 |
waitStatus | int | 节点的等待状态(见下表) |
prev | Node | 前驱节点指针 |
next | Node | 后继节点指针 |
waitStatus的五个取值及含义:
| 常量 | 值 | 含义 |
|---|---|---|
CANCELLED | 1 | 线程取消等待(中断或超时),该节点将被跳过 |
SIGNAL | -1 | 当前节点的后继节点需要被唤醒 |
CONDITION | -2 | 当前节点在Condition条件队列中等待 |
PROPAGATE | -3 | 共享模式下,唤醒操作需要向后传播 |
| 初始状态 | 0 | 节点刚入队,尚未设置任何状态 |
💡 注意:waitStatus的修改不是靠轮询,而是由前驱节点在释放锁时主动设置SIGNAL,再由它调用LockSupport.unpark()唤醒后继-10。这种“前驱通知后继”的设计,是AQS高效性的关键。
五、AQS与Node的关系
AQS是“框架” :提供state变量 + 队列管理的模板方法(如acquire、release)
Node是“载体” :封装每个等待线程的身份和状态
一句话总结:AQS通过state变量和CLH队列管“秩序”,Node节点是队列里的“排队的个体”。两者配合,一个管全局,一个管个体。
六、代码示例:基于AQS实现一个自定义锁
下面展示如何基于AQS实现一个简单的不可重入独占锁:
import java.util.concurrent.locks.AbstractQueuedSynchronizer;public class SimpleLock { // 内部类继承AQS,只需实现tryAcquire和tryRelease private static class Sync extends AbstractQueuedSynchronizer { // 尝试获取锁(独占模式) @Override protected boolean tryAcquire(int arg) { // CAS尝试将state从0改为1 if (compareAndSetState(0, 1)) { setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } // 尝试释放锁 @Override protected boolean tryRelease(int arg) { if (getState() == 0) throw new IllegalMonitorStateException(); setExclusiveOwnerThread(null); setState(0); // 释放锁,state归零 return true; } // 判断当前是否持有锁 @Override protected boolean isHeldExclusively() { return getState() == 1; } } private final Sync sync = new Sync(); public void lock() { sync.acquire(1); } // 获取锁 public void unlock() { sync.release(1); } // 释放锁}使用示例:
public class Main { private static int counter = 0; private static final SimpleLock lock = new SimpleLock(); public static void main(String[] args) throws InterruptedException { Runnable task = () -> { lock.lock(); try { counter++; System.out.println(Thread.currentThread().getName() + " count: " + counter); } finally { lock.unlock(); } }; Thread t1 = new Thread(task); Thread t2 = new Thread(task); t1.start(); t2.start(); t1.join(); t2.join(); }}🔍 执行流程解析:
线程1调用
lock()→sync.acquire(1)→tryAcquire(1)CAS将state从0→1成功 → 获取锁线程2调用
lock()→tryAcquire(1)CAS失败 → AQS将线程2封装成Node加入队列 → 调用LockSupport.park()阻塞线程1调用
unlock()→sync.release(1)→tryRelease(1)将state设为0 → AQS唤醒队列中的线程2线程2被唤醒 → 重新尝试获取锁 → 获取成功
对比:相比手写自旋锁(CPU空转浪费资源),AQS基于LockSupport.park/unpark实现了真正的阻塞与唤醒,高效且可扩展-1。
七、底层原理:AQS的“三根支柱”
理解AQS,只需抓住三根支柱-10:
| 支柱 | 核心元素 | 作用 |
|---|---|---|
| 状态机 | volatile int state | 表示同步资源状态(0空闲,>0被占用/重入计数) |
| 等待队列 | CLH变种队列(双向链表) | 管理等待线程,FIFO排队 |
| 阻塞唤醒 | LockSupport.park() / unpark() | 线程真正的阻塞与唤醒 |
底层技术依赖:
CAS(Compare-And-Swap) :由
Unsafe.compareAndSwapInt实现,保证state状态变更的原子性-3volatile:保证state的修改对所有线程立即可见
LockSupport:基于
park和unpark实现线程阻塞与唤醒,比传统的wait/notify更灵活模板方法模式:
acquire()/release()定义流程骨架,tryAcquire()/tryRelease()留给子类实现-27
⚡ 为什么AQS选择volatile int + CAS,而不是AtomicInteger?
volatile提供最轻量的happens-before保证,且AQS通过Unsafe.compareAndSwapInt直接操作volatile字段,比AtomicInteger多一层封装的写法更高效-19。
八、高频面试题
面试题1:AQS的全称是什么?它的核心设计思想是什么?
标准答案:
全称:AbstractQueuedSynchronizer(抽象队列同步器)-6
核心设计思想:采用模板方法模式,将同步器的核心算法固定,把具体操作留给子类实现。通过一个
volatile int state表示同步状态,一个FIFO等待队列管理线程排队,子类只需重写tryAcquire、tryRelease等方法即可实现不同的同步逻辑-35
踩分点:模板方法、state + 队列、子类重写、独占/共享模式。
面试题2:AQS支持哪两种模式?分别举例说明。
标准答案:
独占模式:同一时刻只有一个线程能获取资源,如ReentrantLock、ReentrantReadWriteLock的写锁-
共享模式:同一时刻多个线程可以同时获取资源,如Semaphore、CountDownLatch-1
踩分点:能说出两种模式的名称并各举1-2个例子。
面试题3:AQS中acquire方法的流程是怎样的?
标准答案(核心四步):
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt();}tryAcquire:尝试直接获取锁(由子类实现),成功则结束
addWaiter:获取失败,将当前线程封装成Node节点,CAS加入队列尾部-1
acquireQueued:在队列中自旋,只有当前驱节点是头节点时才尝试获取锁;失败则调用
LockSupport.park()阻塞-1selfInterrupt:若等待过程中被中断,在获取锁后补发中断-1
踩分点:能说出四步流程,关键术语“tryAcquire→入队→自旋→阻塞”。
面试题4:公平锁和非公平锁的区别是什么?
标准答案:
| 对比维度 | 公平锁 | 非公平锁 |
|---|---|---|
| 获取顺序 | 严格按照申请时间顺序(FIFO) | 允许插队,新线程可先竞争 |
| 性能 | 相对较低,上下文切换多 | 相对更高,减少线程挂起唤醒 |
| 线程饥饿 | 不会发生 | 可能发生 |
ReentrantLock默认是非公平锁,可通过new ReentrantLock(true)创建公平锁-26。
踩分点:能说出核心区别(排队 vs 插队),理解“非公平锁性能更高”的原因——新线程可能直接拿到刚释放的锁,避免内核态挂起/唤醒的开销。
面试题5:Condition和AQS是什么关系?
标准答案:
Condition是AQS的内部类ConditionObject的具体实现。AQS维护两个队列:
同步队列:存放因获取锁失败而阻塞的线程
条件队列:每个Condition对象维护一个等待队列,存放因调用
await()而等待的线程
调用await()时,线程会完全释放锁并进入条件队列;调用signal()时,线程从条件队列被移入同步队列,重新竞争锁-19。
踩分点:区分两种队列、await释放锁、signal转移节点。
九、结尾总结
本文核心回顾:
| 知识点 | 要点 |
|---|---|
| AQS是什么 | AbstractQueuedSynchronizer,Java并发锁的底层框架 |
| 核心组件 | volatile int state + CLH等待队列 + Node节点 |
| 三种关键方法 | tryAcquire(获取)、tryRelease(释放)、acquireQueued(排队) |
| 两种模式 | 独占模式(ReentrantLock)和共享模式(Semaphore) |
| 底层技术 | CAS、volatile、LockSupport、模板方法模式 |
⚠️ 易错点提醒:
AQS是抽象类,不能直接
new AQS(),必须通过子类使用state的修改必须用
compareAndSetState做原子更新,不能直接赋值释放锁后必须唤醒后继线程,否则队列中的线程会永远阻塞
AQS是理解Java并发编程的“敲门砖”。掌握了它,ReentrantLock、Semaphore、CountDownLatch等并发工具的实现原理对你来说都将一目了然。
本文由华丰ai助手整理,希望能帮助你在Java并发学习的道路上更进一步。如有疑问或建议,欢迎交流讨论。
扫一扫微信交流