AQS底层原理

AQS 全称 AbstractQueuedSynchronizer(抽象队列同步器) ,是 Java 并发包(java.util.concurrent.locks)的核心底层框架 ,ReentrantLock、CountDownLatch、Semaphore 等工具都是基于 AQS 实现的。

简单说:AQS 就是一套通用的锁/同步器实现模板,解决了多线程竞争资源时的排队、阻塞、唤醒问题。


一、AQS 核心三大组件

AQS 底层就靠 3 个东西实现所有同步逻辑:

1. 同步状态(state 变量)

  • 用一个 volatile int state 表示资源的占用状态
  • state=0:资源空闲,无线程占用
  • state>0:资源已被占用(重入锁时 state 会累加)
  • 所有线程竞争锁,本质就是修改这个 state 的值

2. 双向链表(CLH 同步队列)

  • 存储抢锁失败的线程,先进先出(FIFO)
  • 每个节点封装:等待线程 + 等待状态 + 前驱/后继节点
  • 作用:线程抢不到锁,就进入队列排队,不浪费 CPU

3. 独占/共享模式

AQS 支持两种同步模式,开箱即用:

  • 独占模式 :只有一个线程能持有锁(ReentrantLock)
  • 共享模式 :多个线程可同时持有锁(CountDownLatch、Semaphore)

二、AQS 核心工作原理(抢锁 + 排队 + 唤醒全流程)

我们以**独占锁(ReentrantLock)**为例,走一遍完整流程:

步骤1:线程尝试抢锁

线程调用 lock() → 调用 AQS 的 tryAcquire(arg) 尝试修改 state:

  1. state=0:用 CAS 原子修改为 1,抢锁成功,当前线程成为锁持有者
  2. state≠0:如果是重入 (当前线程已持有锁),state+1,依然成功
  3. 抢锁失败 → 进入下一步

步骤2:抢锁失败,加入同步队列排队

  1. 把当前线程封装成一个 Node 节点
  2. 用 CAS 安全地加入双向链表尾部
  3. 调用 LockSupport.park() 阻塞当前线程,让出 CPU

步骤3:锁释放,唤醒排队线程

持有锁的线程调用 unlock() → 执行:

  1. state-1,如果 state=0 表示完全释放锁
  2. 唤醒队列头部的第一个等待线程
  3. 被唤醒的线程重新尝试抢锁,成功则出队,成为新的锁持有者

三、AQS 关键技术细节

1. 为什么用 volatile 修饰 state?

  • 保证 多线程之间的可见性:一个线程修改 state,其他线程立刻看到
  • 配合 CAS 实现无锁原子操作,比 synchronized 更轻量

2. 什么是 CAS?

  • 全称:Compare And Swap(比较并交换)
  • 作用:原子性修改 state,不加锁也能保证线程安全
  • 原理:先比较内存值是否为预期值,是就更新,不是就失败重试

3. 队列节点等待状态(waitStatus)

节点的状态控制线程的阻塞/唤醒:

  • 0:默认状态
  • SIGNAL(-1):后继节点需要被唤醒(最常用)
  • CANCELLED(1):线程取消等待
  • CONDITION(-2):在条件队列等待
  • PROPAGATE(-3):共享模式下传播唤醒

4. 公平锁 / 非公平锁

AQS 天然支持两种锁策略:

  • 非公平锁 :线程上来直接抢锁,抢不到再排队(ReentrantLock 默认)
    ✅ 优点:吞吐量高
    ❌ 缺点:可能产生线程"饥饿"
  • 公平锁 :线程先看队列是否为空,有排队线程就直接进队
    ✅ 优点:所有线程公平获取锁
    ❌ 缺点:性能稍低

四、AQS 模板方法设计模式(核心设计思想)

AQS 是抽象类,它只做通用逻辑,具体业务交给子类实现:

AQS 固定实现(不用改)

  • 线程入队、出队
  • 线程阻塞、唤醒
  • 队列维护
  • CAS 修改 state

子类必须实现(定制逻辑)

子类只需要重写这几个方法:

  • tryAcquire():尝试获取独占锁
  • tryRelease():尝试释放独占锁
  • tryAcquireShared():尝试获取共享锁
  • tryReleaseShared():尝试释放共享锁

一句话总结:AQS 搭骨架,子类填逻辑,极大简化了同步器开发。


五、经典 AQS 实现类

工具类 模式 核心原理
ReentrantLock 独占 state=0空闲,state=1占用,重入时state+1
CountDownLatch 共享 state=计数器,countDown()减1,减到0唤醒所有线程
Semaphore 共享 state=许可证数量,acquire()拿证,release()还证
ReentrantReadWriteLock 共享+独占 高16位读锁(共享),低16位写锁(独占)

六、一句话总结 AQS 底层

AQS 使用 volatile state 表示资源状态,用 CLH 双向队列管理抢锁失败的线程,通过 CAS 无锁操作 + LockSupport 阻塞/唤醒,实现了一套高可用的线程同步框架。


总结

  1. 核心三要素 :volatile state(资源)、CLH 队列 (排队)、LockSupport(阻塞唤醒)
  2. 核心流程:尝试抢锁 → 失败入队阻塞 → 释放锁唤醒队首线程
  3. 设计模式:模板方法,AQS 实现通用逻辑,子类定制同步规则
  4. 价值:JUC 所有锁和同步工具的基石,是 Java 高并发的核心底层
相关推荐
weixin_399380691 分钟前
TongWeb7.0.4.9M11如何接入到idea(by lqw)
java·ide·intellij-idea
paopaokaka_luck13 分钟前
社区服务平台(加权协同过滤推荐、Jieba中文词频分析、WebSocket实时聊天、求助处理闭环、 活动积分闭环、ECharts多维分析)
java·前端·spring boot·mysql·echarts·mybatis
.Bryce.19 分钟前
T2-LLM评测不等于Agent评测
android·java·人工智能·后端·gpt·agent·1024程序员节
Wang's Blog21 分钟前
Java 项目实战: 交友项目 - 用户体系集成:查询用户环信账号密码
java·交友
Wang's Blog33 分钟前
Java 项目实战: 交友项目 - 发布评论
java·开发语言·交友
qq_364682151 小时前
录音APP怎么切换语言?多语言版本如何使用
java·服务器·前端
Wang's Blog1 小时前
Java 项目实战: 交友项目 - 用户体系集成:根据环信id查询用户详情
java·lua·交友
摇滚侠1 小时前
《On Java 中文版 基础卷》阅读笔记 复用 13
java·笔记·python
2601_968900771 小时前
玻璃深加工的工艺窗口:4 道工序的温度与时间参数边界
android·java·javascript
薛之谦_1 小时前
用 Java 实现阿里云式 IAM 子用户管理:架构设计与表结构详解
java·python·阿里云