真实面经题目 · 原创解析

AQS 是什么?

AQS 是 Java 并发包中的基础同步框架,用一个 volatile state 表示同步状态,用一个 FIFO 等待队列管理竞争失败的线程,并通过模板方法把通用排队唤醒流程和具体同步语义分离。

出现于:字节跳动 · 后端开发

60 秒回答模板

AQS 可以理解为构建锁和同步器的骨架。它本身不规定 state 代表什么,而是让子类决定:在 ReentrantLock 里 state 是重入次数,在 Semaphore 里 state 是许可数量,在 CountDownLatch 里 state 是计数。AQS 负责提供 acquire、release、排队、阻塞、唤醒、取消等待等通用机制;子类只需要实现 tryAcquire、tryRelease、tryAcquireShared、tryReleaseShared 等方法。它支持独占模式和共享模式,是很多 JUC 组件的底层基础。

考点 状态中心
难度 真实面经高频题
回答目标 讲清机制、边界和追问

深入解析

01

核心定位

AQS 全称 AbstractQueuedSynchronizer,是用来实现锁和同步器的基础框架。它把并发控制拆成两部分:一部分是通用机制,比如线程获取失败后如何排队、如何挂起、释放时如何唤醒后继;另一部分是具体规则,比如 state 等于多少算成功、释放后是否完全可用。这种分层让不同同步组件可以复用同一套队列和调度逻辑。

02

同步状态

AQS 内部最重要的字段是 volatile int state。volatile 保证状态对多线程可见,状态修改通常借助 CAS 保证原子性。AQS 不关心 state 的业务含义,而是交给子类解释。锁可以把它当持有次数,信号量可以把它当许可数,倒计时门闩可以把它当剩余计数。这也是 AQS 能复用到多种同步器的原因。

03

等待队列

当线程获取同步状态失败时,AQS 会把线程封装成节点放入一个近似 CLH 的 FIFO 队列。队列维护前驱和后继关系,线程通常在确认前驱状态合适后才会挂起,释放资源时再唤醒后继节点。这个队列解决了竞争失败线程的组织问题,避免线程在用户态无限自旋消耗 CPU,也能处理取消、超时和中断等复杂情况。

04

模板方法

AQS 的典型设计是模板方法模式。外部调用 acquire 或 release 这类稳定流程,内部再回调子类实现的 tryAcquire、tryRelease 等方法。也就是说,排队、阻塞、唤醒流程由 AQS 控制,是否能拿到资源由子类定义。这样既保证基础并发流程可靠统一,又允许 ReentrantLock、Semaphore、CountDownLatch 等组件表达完全不同的同步语义。

05

独占与共享

AQS 支持独占模式和共享模式。独占模式一次只允许一个线程成功,例如互斥锁;共享模式允许多个线程同时通过,例如读锁或信号量。两种模式都依赖同一个 state 和等待队列,但唤醒传播逻辑不同:独占释放通常唤醒一个后继,共享释放可能继续向后传播,让多个等待线程陆续获得执行机会。

易错点

  • 把 AQS 说成某个具体锁,而不是构建同步器的抽象框架。
  • 只记住 CLH 队列名词,却说不清 state 的语义由子类定义。
  • 认为 AQS 只服务 ReentrantLock,忽略 Semaphore、CountDownLatch、读写锁等组件。
  • 把阻塞唤醒理解成 synchronized 的对象监视器机制,混淆了 LockSupport 和 monitor。

面试官追问

AQS 为什么使用 volatile state?

因为同步状态必须被多个线程及时观察到。volatile 提供可见性和有序性,具体修改再配合 CAS 保证竞争下的原子更新。

AQS 是不是一种锁?

严格说不是。AQS 是实现锁和同步器的框架,ReentrantLock、Semaphore、CountDownLatch 等才是具体组件。

AQS 的队列是普通阻塞队列吗?

不是。它是同步器内部维护的等待队列,节点保存线程和等待状态,配合 LockSupport 挂起与唤醒线程。

独占模式和共享模式的区别是什么?

独占模式一次只允许一个线程获取成功,共享模式允许多个线程基于 state 同时获取成功,释放时也可能产生传播唤醒。