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

AQS与CAS深度讲解

下面我给你 一口气把 AQS 与 CAS 讲透。你有十年 Java 经验,我直接按“面试+底层原理+源码模型”这种工程师能秒懂的方式来讲,不整花里胡哨的。


🔥 一、CAS:并发世界的基石(Compare-And-Swap)

1. CAS 是什么?

一句话:CAS = 无锁原子操作

它做三件事:

CAS(V, E, N):如果 V == E,则把 V 设置为 N,返回 true否则不修改 V,返回 false
  • V:内存地址中的当前值
  • E:期望值
  • N:更新后的新值

谁提供 CAS?
➡ JVM 通过 Unsafe.compareAndSwapXxx() 调用 CPU 指令(x86 的 CMPXCHG
➡ CPU 保证这是“原子的”、线程安全的。

你可以认为 CAS = 硬件级别的乐观锁


2. CAS 的三大问题(面试高频)

✔ 1. ABA 问题

值从 A → B → A,CAS 觉得没变,但其实中间变化过。

解决:

  • AtomicStampedReference(时间戳)
  • AtomicMarkableReference(标记位)

✔ 2. 自旋开销

失败后一直循环重试,导致 CPU 空转。

JDK 做过很多优化:

  • 自适应自旋(spin count 会动态调整)
  • 在锁高竞争时减少自旋

✔ 3. 只能保证一个变量的原子性

要保证多个变量的一致性?
➡ 只能用锁(synchronized / ReentrantLock)。


🔥 二、AQS:Java 锁的地基(AbstractQueuedSynchronizer)

ReentrantLock / Semaphore / CountDownLatch / ReentrantReadWriteLock / FutureTask 都是基于 AQS 实现的。
它是整个 JUC 的地心引力。


1. AQS 的核心思想 — “CLH 双向队列 + CAS 改 state”

AQS 有两个关键点:

✔(1)一个共享变量:state

表示锁是否被持有:

  • 对于 ReentrantLock:
    state = 0 → nobody hold
    state > 0 → 被 hold 并记录重入次数

  • 对于 Semaphore:state = 当前许可数

  • 对于 CountDownLatch:state = 计数

修改 state 时用 CAS


✔(2)一个 FIFO 阻塞队列:CLH(变体)

AQS 内部维护一个双向链表:

head <-> node1 <-> node2 <-> node3 ...

每个 Node 表示一个线程的排队信息:

  • 前驱
  • 后继
  • 等待状态(SIGNAL / CANCELLED / CONDITION)

线程抢锁失败时就会加入这个队列,并在必要时挂起(park)。

这就是“排队 + 挂起 + 唤醒”的核心机制。


🔥 三、AQS 的 acquire() 流程(独占锁)

以 ReentrantLock(非公平锁)为例:

1)尝试 CAS 抢锁

if (compareAndSetState(0, 1)):成功 → 把当前线程设为独占 owner,返回

2)失败 → 入队

加入 CLH 队列尾部

3)进入循环

只要你不是队列头结点的下一个线程,你就继续 park(阻塞)。

4)等待前驱线程释放锁后唤醒

解锁时会:

state = 0
唤醒队列中第一个有效节点

5)被唤醒后再次尝试 CAS 抢锁

如果抢到,成功;否则继续阻塞。


🔥 四、AQS 的 release()(解锁流程)

  1. CAS 减少 state(可重入锁会减到 0 才真正释放)

  2. 如果 state == 0

    • 唤醒队列中的第一个节点(unpark)
  3. 被唤醒的线程再次尝试 CAS 抢锁

整个 AQS 都是“CAS 重试 + park 阻塞 + unpark 唤醒”组成。


🔥 五、公平锁 vs 非公平锁(面试必问)

✔ 非公平锁

先 CAS 抢一次锁,没抢到再排队。
好处:吞吐更高

✔ 公平锁

必须排队,不允许插队。

公平锁流程:

if (没有排队 && state == 0):CAS(0,1)

非公平锁:

CAS(0,1) // 插队

这是它们最关键的区别。


🔥 六、AQS 为什么这么强?

因为它把“加锁/解锁的通用逻辑”抽象出来

  • 排队
  • 阻塞/唤醒
  • CAS 管理 state

然后“子类”只需实现两个方法:

tryAcquire()
tryRelease()

比如 ReentrantLock 实现的就是:

tryAcquire():if (state == 0)CAS(0,1)else if (当前线程 == owner)state++
tryRelease():state--if state == 0:owner = null

CountDownLatch:

tryAcquire()    直接失败
tryRelease()    state-- 到0则唤醒等待线程

Semaphore:

tryAcquire():  state-- >= 0?
tryRelease():  state++

AQS = 队列 + 线程挂起 唤醒机制
锁类 = 定义自己如何修改 state

完美分层。


🔥 七、总结(超快记忆版)

🧱 CAS:

  • 基于 CPU 指令
  • 乐观锁
  • ABA / 自旋问题
  • 修改单变量

🏗 AQS:

  • CLH 双向队列 + CAS 修改 state
  • ReentrantLock / Semaphore / CountDownLatch 的基石
  • acquire/release 模型
  • park/unpark 控制线程

一句话:CAS 是原子性;AQS 是并发框架。

http://www.jsqmd.com/news/69293/

相关文章:

  • 2025年唐老狮权威解读:游戏开发课的体系化构建优势
  • 2025年12月注浆工程厂家推荐:安徽林固,道路注浆、空鼓注浆、公路注浆、路基注浆、地基注浆、厂房注浆、地坪注浆、矿山注浆、多场景注浆解决方案服务商
  • PROFILE
  • PKU 数据结构与算法 2025 复习题 坐公交
  • 2025 雅思培训班怎么选?5 大热门机构深度测评 + 避坑指南
  • day31-GraphRAG
  • 2025年12月模内注塑技术标杆厂商最新推荐:腾达鑫电子科技,引领IML/IMD/IMR/IMP个性化新标准
  • 2025年12月广东佛山智能电动伸缩门厂家TOP推荐:圣田智能科技,安全智能双标杆
  • ISCTF misc+web部分wp
  • CF1046I Say Hello - crazy-
  • church函数与区间算术
  • day31-GraphRAG
  • Python 函数与 lambda 表达式的结合
  • 最短路径 - Dijkstra(堆优化)中优先队列的懒删除如何理解?
  • 116.Java深入学习之JVM二
  • 中小企业走向境外资本市场:境外上市辅导、美股上市实践与中国境外券商投行机构角色——以顺安资本为例
  • 解码生命蓝图,预见健康未来:北京守嘉健康基因检测业务介绍
  • day30-AgentRag应用开发
  • 开放式互联互通的路上,希望畅联云越走越顺
  • 第五十八篇
  • 第五十七篇
  • 2025年12月佛山二手房拍卖机构标杆推荐:佛山房屋拍卖推荐佛山市中正易拍拍卖有限公司
  • 洛谷 P1203 [USACO1.1] 坏掉的项链 Broken Necklace 题解 最短代码|详细
  • 【纯干货分享】计算机毕业设计必看必学(springboot二手车租赁管理专业的系统)原创的定制软件,java、PHP、python、C#小程序、文案全套、毕设程序定制/毕设成品等等.
  • 2025年唐老狮:游戏开发教育商业模式深度解析与性价比评估
  • 2025年12月东营搬家公司推荐:双福搬家,东营搬家搬厂、东营河口搬家、东营垦利搬家、东营市搬家、东营单位搬家、东营设备搬运、全场景搬迁服务标杆
  • 2025年唐老狮全面盘点:游戏开发课的行业积淀与服务价值
  • 2025年12月河南驻马店气体配送优质厂家推荐:河南宏源气体,氧气气体配送、氮气气体配送、氦气气体厂家、二氧化碳气体配送、氩气气体公司、高纯气体配送、多品类气体供应新标杆
  • 2025年唐老狮:游戏开发教育领域深度解析与行业竞争力权威揭秘
  • 吴恩达深度学习课程四:计算机视觉 第一周:卷积基础知识(二)卷积参数