【Java进阶】深度解密 AQS:Java 并发包背后的“灵魂骨架”

🍂 枫言枫语 :我是予枫,一名行走在 Java 后端与多模态 AI 交叉路口的研二学生。

"予一人以深耕,观万木之成枫。"

在这里,我记录从底层源码到算法前沿的每一次思考。希望能与你一起,在逻辑的丛林中寻找技术的微光。

在 Java 面试或者研读源码时,你一定会被问到:ReentrantLock 是怎么实现的?CountDownLatch 为什么能让线程等待?这些看似功能迥异的组件,其实背后都指向了同一个名字------AQS

今天,我来带大家拆解这个 Doug Lea 大神留下的神作。


一、 AQS 到底是什么?

AQS ,全称 AbstractQueuedSynchronizer(抽象队列同步器)。

简单来说,它是一个框架。它把实现一个锁(或同步器)最繁琐的工作(比如线程排队、线程阻塞与唤醒、CAS 操作状态等)全部封装好了。你只需要在这个框架的基础上,填入一点点关于"如何获取锁"和"如何释放锁"的业务逻辑,就能造出一把功能完备的锁。

形象比喻:自动化的银行柜台

想象一个只有一个柜台的银行:

  • State(状态): 柜台是否有人(0 表示空闲,1 表示有人)。

  • CAS: 客户尝试冲向柜台的动作。

  • CLH 队列: 没抢到柜台的人,自觉去排队。

  • AQS 框架: 银行的自动排队机和叫号系统。它负责维护队列,并在柜台空闲时,叫醒下一个人。


二、 AQS 的"三大支柱"

要理解 AQS,必须死磕这三个核心组成部分:

1. 状态位:volatile int state

这是 AQS 的核心。所有的同步状态都靠它。

  • ReentrantLock 中,state 表示锁的持有次数(0 为空闲,1 为被占用,>1 为重入次数)。

  • Semaphore 中,state 表示剩余的可用许可数。

  • CountDownLatch 中,state 表示还需要等待的计数。

注意: state 是被 volatile 修饰的,保证了多线程下的可见性。

2. CAS (Compare And Swap)

AQS 频繁使用 CAS 指令来修改 state 的值。这是实现"无锁化"或"轻量级锁"的关键。只有 CAS 成功的线程,才算真正拿到了锁。

3. CLH 变体队列(双向链表)

当线程抢锁失败时,AQS 会将其封装成一个 Node 节点,并放入一个双向链表中。

  • 头节点 (Head): 正在持有锁的那个线程。

  • 后续节点: 正在苦苦等待被唤醒的线程。


三、 AQS 的两种工作模式

AQS 设计最精妙的地方在于它同时支持两种模式:

  1. 独占模式 (Exclusive):

    一次只能有一个线程持有锁。如 ReentrantLock。

  2. 共享模式 (Shared):

    允许多个线程同时获取。如 Semaphore(信号量)、ReadLock(读锁)、CountDownLatch。

这种"一套框架,两样通吃"的设计,体现了极高的抽象能力。


四、 源码级流程:一个线程的"抢锁之旅"

我们以 ReentrantLock.lock() 为例,看看 AQS 内部发生了什么:

第一步:acquire(1)

线程尝试获取锁。

  • 调用 tryAcquire(1)。这个方法是由具体的子类(如 NonfairSync)实现的。

  • 如果成功(CAS 修改 state 从 0 变 1 成功),直接开干。

第二步:addWaiter(Node.EXCLUSIVE)

如果 tryAcquire 失败了,AQS 会把当前线程包装成一个 Node,塞进队列的尾部。这里用到了"自旋 + CAS"来保证线程安全地入队。

第三步:acquireQueued(node, 1)

这是最精彩的部分。线程入队后不会立即睡觉(挂起),而是会再看一眼:"我的前驱节点是不是头节点?"

  • 如果是,说明快轮到我了,再试一次 tryAcquire

  • 如果不是,或者再次尝试也失败了,那就调用 LockSupport.park(this),心安理得地阻塞休眠


五、 为什么 AQS 这么快?

  1. 自旋优化: 线程在进入阻塞状态前,会进行少量的自旋尝试,减少了内核态和用户态切换的开销。

  2. 双向链表: 便于取消某个排队节点(比如等待超时的线程),只需要修改前后指针即可。

  3. 模板方法模式: AQS 定义了骨架,复杂的线程调度逻辑由 AQS 处理,子类只需关心简单的状态修改逻辑。


六、 给"予枫"读者的总结

AQS 的精髓在于:它通过一个 volatile 状态位和一个高效的 FIFO 队列,完美地解决了多线程抢占资源的冲突问题。

如果你在准备面试,记住这几个关键词:volatile stateCAS双向 CLH 队列LockSupport


下一步建议

单纯看博文是不够的。建议你打开 IntelliJ IDEA,输入 ReentrantLock,顺着 lock() 方法点进去,看看那个叫 Sync 的内部类,你会发现它真的继承了 AbstractQueuedSynchronizer

关于作者 : 💡 予枫 ,某高校在读研究生,专注于 Java 后端开发与多模态情感计算。💬 欢迎点赞、收藏、评论,你的反馈是我持续输出的最大动力!
我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:

https://cloud.tencent.com/developer/support-plan?invite_code=9wrxwtlju1l

当前加入还有惊喜相送!

相关推荐
NAGNIP10 小时前
一文搞懂深度学习中的通用逼近定理!
人工智能·算法·面试
冬奇Lab12 小时前
一天一个开源项目(第36篇):EverMemOS - 跨 LLM 与平台的长时记忆 OS,让 Agent 会记忆更会推理
人工智能·开源·资讯
冬奇Lab12 小时前
OpenClaw 源码深度解析(一):Gateway——为什么需要一个"中枢"
人工智能·开源·源码阅读
AngelPP15 小时前
OpenClaw 架构深度解析:如何把 AI 助手搬到你的个人设备上
人工智能
宅小年15 小时前
Claude Code 换成了Kimi K2.5后,我再也回不去了
人工智能·ai编程·claude
九狼16 小时前
Flutter URL Scheme 跨平台跳转
人工智能·flutter·github
ZFSS16 小时前
Kimi Chat Completion API 申请及使用
前端·人工智能
天翼云开发者社区17 小时前
春节复工福利就位!天翼云息壤2500万Tokens免费送,全品类大模型一键畅玩!
人工智能·算力服务·息壤
知识浅谈17 小时前
教你如何用 Gemini 将课本图片一键转为精美 PPT
人工智能
Ray Liang18 小时前
被低估的量化版模型,小身材也能干大事
人工智能·ai·ai助手·mindx