真实面经题目 · 原创解析
AQS 是什么?
AQS 是 Java 并发包中的基础同步框架,用一个 volatile state 表示同步状态,用一个 FIFO 等待队列管理竞争失败的线程,并通过模板方法把通用排队唤醒流程和具体同步语义分离。
真实面经题目 · 原创解析
AQS 是 Java 并发包中的基础同步框架,用一个 volatile state 表示同步状态,用一个 FIFO 等待队列管理竞争失败的线程,并通过模板方法把通用排队唤醒流程和具体同步语义分离。
AQS 可以理解为构建锁和同步器的骨架。它本身不规定 state 代表什么,而是让子类决定:在 ReentrantLock 里 state 是重入次数,在 Semaphore 里 state 是许可数量,在 CountDownLatch 里 state 是计数。AQS 负责提供 acquire、release、排队、阻塞、唤醒、取消等待等通用机制;子类只需要实现 tryAcquire、tryRelease、tryAcquireShared、tryReleaseShared 等方法。它支持独占模式和共享模式,是很多 JUC 组件的底层基础。
AQS 全称 AbstractQueuedSynchronizer,是用来实现锁和同步器的基础框架。它把并发控制拆成两部分:一部分是通用机制,比如线程获取失败后如何排队、如何挂起、释放时如何唤醒后继;另一部分是具体规则,比如 state 等于多少算成功、释放后是否完全可用。这种分层让不同同步组件可以复用同一套队列和调度逻辑。
AQS 内部最重要的字段是 volatile int state。volatile 保证状态对多线程可见,状态修改通常借助 CAS 保证原子性。AQS 不关心 state 的业务含义,而是交给子类解释。锁可以把它当持有次数,信号量可以把它当许可数,倒计时门闩可以把它当剩余计数。这也是 AQS 能复用到多种同步器的原因。
当线程获取同步状态失败时,AQS 会把线程封装成节点放入一个近似 CLH 的 FIFO 队列。队列维护前驱和后继关系,线程通常在确认前驱状态合适后才会挂起,释放资源时再唤醒后继节点。这个队列解决了竞争失败线程的组织问题,避免线程在用户态无限自旋消耗 CPU,也能处理取消、超时和中断等复杂情况。
AQS 的典型设计是模板方法模式。外部调用 acquire 或 release 这类稳定流程,内部再回调子类实现的 tryAcquire、tryRelease 等方法。也就是说,排队、阻塞、唤醒流程由 AQS 控制,是否能拿到资源由子类定义。这样既保证基础并发流程可靠统一,又允许 ReentrantLock、Semaphore、CountDownLatch 等组件表达完全不同的同步语义。
AQS 支持独占模式和共享模式。独占模式一次只允许一个线程成功,例如互斥锁;共享模式允许多个线程同时通过,例如读锁或信号量。两种模式都依赖同一个 state 和等待队列,但唤醒传播逻辑不同:独占释放通常唤醒一个后继,共享释放可能继续向后传播,让多个等待线程陆续获得执行机会。
因为同步状态必须被多个线程及时观察到。volatile 提供可见性和有序性,具体修改再配合 CAS 保证竞争下的原子更新。
严格说不是。AQS 是实现锁和同步器的框架,ReentrantLock、Semaphore、CountDownLatch 等才是具体组件。
不是。它是同步器内部维护的等待队列,节点保存线程和等待状态,配合 LockSupport 挂起与唤醒线程。
独占模式一次只允许一个线程获取成功,共享模式允许多个线程基于 state 同时获取成功,释放时也可能产生传播唤醒。