当前位置: 首页 > news >正文

Java并发之AQS详解

目录
  • Java并发之AQS详解
    • 1. AQS 是什么?
    • 2. 核心原理
      • 2.1 一个状态:state
      • 2.2 一个队列:CLH 变种队列
      • 2.3 一套模板方法:获取与释放
    • 3. 工作流程(以 ReentrantLock 的独占模式为例)
      • 3.1 获取锁 (lock() -> acquire(1))
      • 3.2 释放锁 (unlock() -> release(1))
    • 4. 主要同步器实现
    • 5. Synchronized 、Lock、Condition、AQS
    • 6. 总结与要点

Java并发之AQS详解

Java并发之AQS详解 - waterystone - 博客园

1. AQS 是什么?

AQS,全称 AbstractQueuedSynchronizer(抽象队列同步器),是 Java 并发包 java.util.concurrent.locks 下的一个核心基础框架。

它的主要作用是为构建锁和同步器(如 Semaphore、CountDownLatch 等)提供一个底层的、通用的同步机制。你可以把它想象成一个“同步器的骨架”,它帮你处理了复杂的线程排队、阻塞、唤醒等底层细节,你只需要按需实现一些关键的方法,就能定制出自己的同步工具。

核心思想:如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制 AQS 是用 CLH 队列锁 实现的,即将暂时获取不到锁的线程加入到队列中。

一句话总结:AQS 是 JUC 锁的“大脑”,它管理着线程的排队、阻塞和唤醒。


2. 核心原理

AQS 的核心原理可以概括为三部分:一个状态一个队列一套模板方法

2.1 一个状态:state

AQS 内部维护了一个关键的 volatile 整型变量,名为 state

  • 作用state 表示共享资源的状态。具体含义由子类定义,非常灵活。
  • 示例
    • ReentrantLock 中,state=0 表示锁空闲,state=1 表示锁被占用,state>1 表示锁被同一个线程重入。
    • Semaphore 中,state 表示可用的许可证数量。
    • CountDownLatch 中,state 表示倒计数的数值。

state 的修改使用 CAS(Compare-And-Swap)操作来保证原子性,这是实现非阻塞同步的基础。

2.2 一个队列:CLH 变种队列

AQS 内部维护了一个双向的 FIFO 线程等待队列(通常被称为 CLH 队列的变种)。当线程获取资源失败时,AQS 会将该线程以及其等待状态(如是否独占)包装成一个 Node 节点,并将其加入到队列尾部,然后阻塞该线程。

  • Node 节点:包含了线程引用、等待状态(如 CANCELLED, SIGNAL 等)、前驱节点(prev)和后继节点(next)。
  • 作用:这个队列是所有未能立即获取到资源的线程的“等候室”,它严格保证了等待的公平性(FIFO)。

2.3 一套模板方法:获取与释放

AQS 使用了 模板方法设计模式。它定义了一套顶层的获取和释放资源的流程(如 acquire(int arg)release(int arg)),而将一些关键的是否成功、如何修改状态的判断留给子类去实现。

子类需要重写的关键方法

  • protected boolean tryAcquire(int arg):尝试以独占方式获取资源。成功则返回 true,失败则返回 false。
  • protected boolean tryRelease(int arg):尝试以独占方式释放资源。成功则返回 true,失败则返回 false。
  • protected int tryAcquireShared(int arg):尝试以共享方式获取资源。负数表示失败;0 表示成功,但无剩余可用资源;正数表示成功,且有剩余资源。
  • protected boolean tryReleaseShared(int arg):尝试以共享方式释放资源。

AQS 提供的核心模板方法(供使用者调用)

  • 独占模式
    • acquire(int arg):获取资源,如果失败则进入队列等待。此过程不可中断。
    • release(int arg):释放资源,成功后唤醒队列中下一个等待的线程。
  • 共享模式
    • acquireShared(int arg)
    • releaseShared(int arg)

3. 工作流程(以 ReentrantLock 的独占模式为例)

我们以锁的获取和释放来看 AQS 是如何工作的。

3.1 获取锁 (lock() -> acquire(1))

  1. 线程 A 调用 lock()
  2. lock() 内部会调用 AQS 的 acquire(1)
  3. acquire(1) 的流程如下:
    1. tryAcquire(1):子类(ReentrantLock 的 Sync)实现此方法。检查 state
      • 如果 state == 0(锁空闲),则通过 CAS 将其设为 1,并设置当前线程为独占线程,返回 true。流程结束,线程 A 获得锁。
      • 如果 state != 0,但独占线程就是线程 A 自己(锁重入),则将 state 加 1,返回 true
      • 否则,返回 false
    2. 如果 tryAcquire 返回 false(获取失败),则调用 addWaiter(Node.EXCLUSIVE)。将线程 A 包装成一个独占模式的 Node 节点,并采用 CAS 方式安全地插入到等待队列的尾部。
    3. 接着调用 acquireQueued(...)。这个方法是核心中的核心:
      • 它会让节点自旋地尝试获取锁(在它即将成为队首时)。
      • 如果还是失败,则会判断是否应该阻塞自己(通过前驱节点的 waitStatus)。
      • 最终,通过 LockSupport.park() 将线程 A 挂起(阻塞)

3.2 释放锁 (unlock() -> release(1))

  1. 线程 A 调用 unlock()
  2. unlock() 内部会调用 AQS 的 release(1)
  3. release(1) 的流程如下:
    1. tryRelease(1):子类实现此方法。将 state 减 1。如果 state 减到 0,表示锁完全释放,清空独占线程,返回 true
    2. 如果 tryRelease 返回 true,则它会找到等待队列中的头节点(head)。
    3. 如果头节点不为空且其状态有效,则调用 unparkSuccessor(Node node)
    4. 这个方法会使用 LockSupport.unpark(thread) 唤醒 头节点后继节点中第一个未被取消的线程(假设是线程 B)。
  4. 线程 B 被唤醒后,会从之前在 acquireQueued 中被 park() 的地方继续执行。
  5. 线程 B 会再次自旋尝试 tryAcquire。此时锁已被线程 A 释放,所以线程 B 有很大概率成功获取到锁,然后将自己设置为新的头节点,继续执行。

4. 主要同步器实现

AQS 是 JUC 中众多同步工具的基础:

  • ReentrantLock:独占锁,使用 AQS 的独占模式。
  • ReentrantReadWriteLock:读写锁。其读锁使用共享模式,写锁使用独占模式。
  • Semaphore:信号量,使用 AQS 的共享模式。
  • CountDownLatch:倒计时器,使用 AQS 的共享模式。state 初始化为计数。
  • CyclicBarrier:循环栅栏(其底层使用了 ReentrantLock 和 Condition,而 Condition 的实现也依赖于 AQS)。
  • ThreadPoolExecutor:线程池中的 Worker 类(工作线程)也使用了 AQS 来实现独占锁,用于判断线程是否空闲。

5. Synchronized 、Lock、Condition、AQS

AQS 使用 CAS + volatile state + CLH队列,比传统的 synchronized 有更好的并发性能。

  • Lock 替代原始的 synchronized
  • Condition 替代原始的 wait/notify
  • 主流的 LockCondition 实现都是基于 AQS

synchronized 和 Lock (基于AQS)

原始方式 (JDK 1.0+)         现代方式 (JDK 5+)
synchronized     →    Lock (基于AQS)
wait/notify      →    Condition (基于AQS)
// 原始的 wait/notify
synchronized (lock) {while (!condition) {lock.wait();  // 所有等待者混在一起}// ...lock.notifyAll();  // 唤醒所有等待者
}// 现代的 Condition
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();lock.lock();
try {while (!condition) {condition.await();  // 只等待特定条件}// ...condition.signal();  // 只唤醒一个等待此条件的线程
} finally {lock.unlock();
}// 现代的 Condition Lock 提供更多功能if (lock.tryLock(1, TimeUnit.SECONDS)) {  // 尝试获取锁,带超时try {// ...} finally {lock.unlock();}
}
// 锁中断
lock.lockInterruptibly();  // 可中断的锁获取Lock lock = new ReentrantLock();
Condition notFull = lock.newCondition();   // 队列未满条件
Condition notEmpty = lock.newCondition();  // 队列非空条件
// 生产者只等待 notFull 条件
// 消费者只等待 notEmpty 条件
// 互不干扰!

6. 总结与要点

  • 定位:AQS 是构建锁和同步器的框架,不是直接给业务开发者使用的类。
  • 核心机制:通过一个 volatilestate 表示状态,一个 FIFO 队列管理等待线程,一套 CAS 操作保证状态更新的原子性。
  • 设计模式:模板方法模式。使用者继承 AQS 并重写指定方法,将 AQS 组合在自定义同步组件的实现中。
  • 两种模式独占模式(一次只有一个线程能执行,如 ReentrantLock)和共享模式(多个线程可同时执行,如 Semaphore/CountDownLatch)。
  • 重要性:理解了 AQS,就理解了 JUC 包中大部分同步工具的实现原理,是 Java 并发编程进阶的必经之路。

通过 AQS,Java 提供了一种高效、安全且可扩展的方式来构建复杂的同步结构,极大地简化了并发编程的难度。

http://www.hskmm.com/?act=detail&tid=32994

相关文章:

  • 从“看得见”到“看得懂”:国标GB28181算法算力平台EasyGBS与公安安防数字化的深度融合
  • 2025 年优法兰品牌最新推荐榜:优法兰骨相支撑、优法兰魔法 CC 针、优法兰 CaHA、优法兰骨相塑形、优法兰面部注射填充剂五大国内医美品牌专利技术、市场口碑及选择指南全景解析
  • 10.13课后作业 - GENGAR
  • 山海鲸可视化可以导入哪些常用的3D模型?
  • 2025 年光谱仪厂家最新推荐排行榜:便携式 / 有色金属 / X 射线荧光等多类型设备优质厂家深度解析
  • 2025 年分析仪生产厂家最新推荐榜单:覆盖便携式、有色金属、荧光等多类分析仪,帮企业选靠谱优质品牌
  • Kafka、RabbitMQ、RocketMQ、ZeroMQ等 消息中间件 介绍和对比
  • 猪脚与猪脚饭与猪脚饭之店
  • 2025年10月中国高端医美机构推荐榜单:安全认证与专家资质全解析
  • 读书笔记:什么时候该用B*树索引?一个接地气的解读
  • 2025年工作服厂家权威推荐榜:防静电/劳保/国网/餐厅/工厂/电工/防酸碱/电力/车间/航空/员工工作服,文化衫/T恤/POLO衫/冲锋衣全品类精选
  • 消息推送策略:如何在营销与用户体验间找到最佳平衡点
  • ONLYOFFICE Docs 9.1正式发布:更强大的PDF编辑器、更快的公式性能、超500项优化!
  • 全球最佳承包商管理平台深度解析
  • HTTP 和 TCP 的关系与区别
  • cucumber7+junit5
  • 剪映VIP全功能永久解锁后,我的剪辑效率直接翻倍!
  • 零碳园区建设指南:MyEMS 如何用数字化破解能耗与碳排放协同管理难题?
  • 误删 Stash 后的数据恢复实践
  • mysql开启binlog日志,完全配置指南
  • 2025年10月固定资产管理系统推荐榜单:基于全生命周期功能对比与行业适配度评测
  • Linux MegaCli RAID 控制管理工具详解
  • 2025年10月重庆保洁公司推荐对比榜:用数据还原真实服务能力
  • 2025年10月重庆保洁公司推荐排名:聚焦服务细节与合规风险的避坑手册
  • 2025 房屋改造公司最新推荐榜:聚焦老房 / 局部 / 小户型需求的口碑深度测评,花小钱住好家必看
  • 2025年10月床垫品牌推荐榜:十强对比与中立评测助你安心选购
  • uni-app x商城,商品列表组件封装以及使用
  • 深入解析:【Proteus8.17仿真】 STM32仿真 0.96OLED 屏幕显示ds1302实时时间
  • 2025年10月床垫品牌推荐榜:围绕环保认证与试睡政策的系统化评析
  • 贪心策略总结