此篇主要针对大家感兴趣的AQS详细说明,欢迎评论区指正!
一、AQS究竟是什么?
AQS(AbstractQueuedSynchronizer) 不是一个具体的锁,而是一个构建锁和同步器的框架。你可以把它想象成汽车工厂的"底盘平台":同样的底盘可以造出轿车、SUV、卡车等各种车型。


二、为什么需要AQS?解决了什么问题?
1. 问题背景
在AQS出现之前,Java只有synchronized关键字实现同步,但它存在局限:
- 无法实现公平锁
- 没有超时等待机制
- 没有条件变量的精细控制
- 无法中断一个正在等待的线程
2. AQS的解决方案
AQS提供了一个通用的并发控制框架,让开发者可以:
- 自定义各种锁策略
- 实现复杂的同步需求
- 获得更好的性能
三、AQS的架构和工作原理
核心结构:CLH队列 + 状态变量


关键代码:AQS核心方法
java
public abstract class AbstractQueuedSynchronizer { private volatile int state; private transient volatile Node head; private transient volatile Node tail; static final class Node { volatile Node prev; volatile Node next; volatile Thread thread; volatile int waitStatus;
AQS 的两种同步模式
独占模式(Exclusive Mode)
-
特点:同一时刻仅允许一个线程持有资源。
-
典型应用 :
ReentrantLock、CountDownLatch。 -
核心方法:
-
acquire(int arg):获取资源(失败则入队阻塞)。 -
release(int arg):释放资源(唤醒后继节点)。
acquire 流程


共享模式(Shared Mode)
-
特点:允许多个线程同时持有资源(如读锁、信号量)。
-
典型应用 :
Semaphore、ReentrantReadWriteLock的读锁。 -
核心方法:
-
acquireShared(int arg):获取共享资源。 -
releaseShared(int arg):释放共享资源(可能唤醒多个后继)。
releaseShared 的传播性
scss
private void doReleaseShared() { if (h != null && h != tail) { int ws = h.waitStatus; if (ws == Node.SIGNAL) { if (compareAndSetWaitStatus(h, Node.SIGNAL, 0)) unparkSuccessor(h); // 唤醒后继 else if (ws == 0) compareAndSetWaitStatus(h, 0, Node.PROPAGATE); if (h == head) break; // 若head未变则退出
四、实际开发中如何与AQS交互
场景1:使用现成的AQS实现
普通开发不需要直接使用AQS,而是使用基于AQS的工具类:
java
import java.util.concurrent.locks.ReentrantLock;import java.util.concurrent.CountDownLatch;import java.util.concurrent.Semaphore;public class AQSInPractice { public static void main(String[] args) throws InterruptedException { // 1. ReentrantLock - 可重入锁 ReentrantLock lock = new ReentrantLock(true); // true表示公平锁 System.out.println("锁已获取"); lock.unlock(); // 2. CountDownLatch - 线程协调 CountDownLatch latch = new CountDownLatch(3); for (int i = 0; i < 3; i++) { new Thread(() -> { latch.countDown(); latch.await(); // 等待所有线程完成 System.out.println("所有任务完成"); // 3. Semaphore - 信号量 Semaphore semaphore = new Semaphore(3); // 允许3个线程同时访问 semaphore.acquire(); semaphore.release();
场景2:扩展AQS实现自定义同步器
可以继承AQS实现自定义同步需求:
ruby
import java.util.concurrent.locks.AbstractQueuedSynchronizer;// 一个简单的"最多允许N个线程访问"的自定义锁public class SimpleLimitLock { private final Sync sync; public SimpleLimitLock(int limit) { sync = new Sync(limit); private static class Sync extends AbstractQueuedSynchronizer { Sync(int limit) { setState(limit); // 初始化状态为允许的最大线程数 protected int tryAcquireShared(int acquires) { int available = getState(); int remaining = available - acquires; // 如果剩余许可不足或CAS成功,返回结果 if (remaining < 0 || compareAndSetState(available, remaining)) { return remaining; protected boolean tryReleaseShared(int releases) { int current = getState(); int next = current + releases; if (compareAndSetState(current, next)) { return true; sync.acquireShared(1); public void unlock() { sync.releaseShared(1);
五、AQS在Java并发体系中的角色
scss
// Java并发编程的层次结构:
┌─────────────────────────────────────────────────┐
│ Java并发应用层 │
│ • 线程池 (ExecutorService) │
│ • 并发集合 (ConcurrentHashMap) │
│ • 异步任务 (CompletableFuture) │
├─────────────────────────────────────────────────┤
│ AQS工具类层 │
│ • ReentrantLock │
│ • Semaphore │
│ • CountDownLatch │
│ • CyclicBarrier │
├─────────────────────────────────────────────────┤
│ AQS框架层 │
│ • 状态管理 (state) │
│ • 队列管理 (CLH队列) │
│ • 线程阻塞/唤醒 (LockSupport) │
├─────────────────────────────────────────────────┤
│ JVM/OS层 │
│ • synchronized监视器锁 │
│ • CAS指令 (Unsafe类) │
│ • 线程调度 (操作系统) │
└─────────────────────────────────────────────────┘
六、AQS的工作流程示例
以ReentrantLock的加锁过程为例:
ruby
sync.acquire(1); // 调用AQS的模板方法 abstract static class Sync extends AbstractQueuedSynchronizer { // AQS.acquire()的调用链: // 1. tryAcquire() 尝试获取锁(子类实现) // 2. addWaiter() 创建节点加入队列 // 3. acquireQueued() 在队列中自旋/阻塞 // 4. 如果被中断过,自我中断恢复状态
具体过程可以用图表示:


七、实际开发中的最佳实践
1. 选择合适的同步工具
csharp
public class SyncToolSelection { void useReentrantLock() { ReentrantLock lock = new ReentrantLock(true); // 公平锁 void useSemaphore() { Semaphore semaphore = new Semaphore(10); // 最多10个线程同时访问 // 适用于数据库连接池、限流场景 void useCountDownLatch() { CountDownLatch latch = new CountDownLatch(5); // 适用于启动阶段等待初始化完成 void useCyclicBarrier() { CyclicBarrier barrier = new CyclicBarrier(4); // 适用于并行计算,等待所有线程到达屏障
2. 避免常见陷阱
vbnet
public class AQSPitfalls { ReentrantLock lock = new ReentrantLock(); if (someCondition) { return; // 这里直接返回,忘记解锁! lock.unlock(); // 必须在finally中释放 void conditionVariableMistake() { ReentrantLock lock = new ReentrantLock(); Condition condition = lock.newCondition(); // 错误:没有在lock保护下调用await // condition.await(); condition.await(); lock.unlock();
八、总结:AQS在并发编程中的角色
- 框架提供者:为锁和同步器提供通用实现框架
- 基础设施:是Java并发包的基石,如大楼的地基
- 性能优化:相比synchronized提供更灵活的优化空间
- 功能扩展:支持公平/非公平、可重入、读写分离等高级特性