JUC AQS
·
AQS(AbstractQueuedSynchronizer)是Java并发包的基础框架,它封装了实现同步器(如ReentrantLock、Semaphore等)所需的核心逻辑,让开发者能轻松构建自定义的并发工具。
核心设计思路
-
资源状态管理
用一个volatile int state表示共享资源的状态:state = 0表示资源空闲;- 可根据需要表示不同含义(如锁的重入次数、信号量的剩余许可证数)。
使用volatile保证多线程间的可见性,并通过 CAS(Compare-And-Swap) 原子地修改state,避免加锁开销。
-
等待队列
当CAS修改state失败(即资源被占用)时,线程不能一直自旋浪费CPU,而是需要被阻塞。AQS 用 双向链表 实现了一个 FIFO 等待队列(CLH锁的变体),将获取资源失败的线程封装成Node节点入队,并通过LockSupport.park/unpark实现线程的阻塞与唤醒。队列结构也为实现 公平策略 提供了基础(先入队的线程优先获得资源)。 -
模板方法模式
AQS 定义了资源获取与释放的骨架,但将具体的获取逻辑(如是否允许重入、是否允许插队)留给子类实现。典型方法如:tryAcquire():尝试获取资源(返回 boolean),由子类重写;acquire():若tryAcquire()失败,则将当前线程入队并阻塞,直到被唤醒后再次尝试。
这样既复用了排队、阻塞等通用逻辑,又保留了灵活性。
-
独占模式与共享模式
- 独占模式(如 ReentrantLock):同一时刻只允许一个线程访问资源,
state通常表示锁的持有次数(可重入)。 - 共享模式(如 Semaphore、CountDownLatch):允许多个线程同时访问,
state表示剩余许可证数或需等待的任务数。
- 独占模式(如 ReentrantLock):同一时刻只允许一个线程访问资源,
-
条件队列(Condition)
AQS 通过内部ConditionObject实现了类似Object.wait/notify的线程等待/唤醒机制。每个Condition维护一个独立的条件队列,调用await()的线程会释放资源并进入条件队列等待;signal()则将条件队列中的节点移到等待队列,等待重新竞争资源。支持创建多个Condition,实现更精细化的线程协调。
为什么不用操作系统 Mutex?
- 性能:直接使用内核态的
mutex会频繁触发用户态/内核态切换,开销大。AQS 基于用户态的 CAS 和队列管理,在竞争不激烈时避免了系统调用。 - 灵活性:AQS 在 Java 层面提供了可扩展的模板,允许开发者自定义公平策略、共享/独占模式等,而操作系统原语无法直接实现这种灵活性。
与 synchronized 的对比
- 可中断与超时:ReentrantLock 基于 AQS 的
tryAcquire可提供tryLock超时、中断响应等能力,而synchronized不支持。 - 公平性:AQS 的队列结构让 ReentrantLock 能轻松实现公平锁(先来后到),
synchronized只能是非公平锁。 - 条件队列:ReentrantLock 可创建多个
Condition实现精准唤醒,synchronized仅支持单一的wait/notify集。
简言之,AQS 通过 状态变量(state)+ CAS + 等待队列 + 模板方法 构建了一个高效、灵活的多线程同步框架,成为 Java 并发工具(如 ReentrantLock、Semaphore、CountDownLatch 等)的基石。
更多推荐



所有评论(0)