CAS讲解

一、核心执行逻辑

CAS 操作包含三个操作数:内存地址 V、预期旧值 A、要写入的新值 B。 执行三步原子操作:

  1. 读取内存地址 V 上当前值;
  2. 判断当前值是否等于预期旧值 A;
  3. 两种结果:
    • 相等:说明期间没有其他线程修改,把新值 B 写入 V,操作成功;
    • 不相等:说明数据被其他线程改动过,本次修改失败,不写入。

通常搭配自旋重试:失败后循环再次执行 CAS,直到成功。

示例:实现自增 count++

  1. 获取当前 count=10(预期 A=10)
  2. 计算新值 B=11
  3. CAS (V,A,B) 若内存还是 10 → 更新为 11; 若已经变成 11,说明被别的线程改过,重试。

二、底层实现

Java 中 CAS 底层依赖 Unsafe 类提供的 native 方法,由 CPU 硬件指令保证原子性: compareAndSwapInt()compareAndSwapLong() 依靠 CPU 的cmpxchg 硬件指令,一条指令完成比较 + 交换,不会被线程中断,天然原子,不需要加锁。

三、典型使用场景

  1. JUC 原子类:AtomicInteger、AtomicLong、AtomicReference,无锁实现计数;
  2. synchronized 轻量级锁自旋抢锁底层;
  3. 并发容器:ConcurrentHashMap 更新节点、计数器;
  4. 自旋锁、乐观锁自定义实现。

四、CAS 三大经典问题

1. ABA 问题

场景:线程 1 读取值 A,线程 2 先把 A 改成 B,再改回 A;线程 1 执行 CAS 时发现还是 A,误以为没被修改,实际中间发生过改动。 解决:版本号机制,每次修改带上自增版本,比较时同时校验版本。AtomicStampedReference 带版本戳原子引用。

2. 自旋消耗 CPU

大量线程竞争下,CAS 不断循环重试,持续占用 CPU,空耗资源。 解决:限制自旋次数、竞争激烈时降级为重量级锁。

3. 只能保证单个变量原子操作

无法一次性对多个共享变量做 CAS 原子更新,多变量同步还是需要锁。

五、CAS 乐观锁 vs synchronized 悲观锁

  1. CAS 乐观锁:无阻塞,不切换内核态,竞争少性能高;竞争激烈 CPU 消耗大,存在 ABA 缺陷;
  2. synchronized 悲观锁:竞争失败线程阻塞挂起,释放 CPU;内核切换开销大,无 ABA 问题。

精简总结口述版

CAS 是比较并交换的无锁乐观锁,基于 CPU 硬件指令保证原子;先对比内存值与预期值,一致才更新,失败自旋重试;存在 ABA、CPU 空转、多变量无法原子更新三大问题;AtomicInteger、轻量级锁底层都使用 CAS。

相关推荐
机建狂魔几秒前
Codex 接入第三方模型 API 实战:以 Mimo 为例
java·服务器·数据库·ai·ai编程·codex
山峰哥27 分钟前
数据库工程与SQL调优:从慢查询到秒级响应的实战之路
java·开发语言·数据库·sql·深度优先·启发式算法
乐观的Terry29 分钟前
11、发布系统-用户认证与权限体系
java·spring boot·spring·spring cloud·mybatis
前端开发张小七29 分钟前
Java 学习笔记 · 第二课:面向对象核心(封装、继承、多态)及接口与异常
java·后端·程序员
wangjialelele36 分钟前
Selenium4 + Java Web自动化测试入门指南:从环境搭建到常用操作详解
java·开发语言·前端·测试工具·自动化
孙启超1 小时前
【AI应用开发】LangChain 中 Chain 和 Agent 核心区别?
java·人工智能·langchain·llm·rag·ai应用开发·agent loop
leoZ2311 小时前
实战复盘:用 Claude Code 从零搭一个 GitHub PR 统计工具
java·人工智能·python·深度学习·自然语言处理·github·llama
William Dawson1 小时前
【踩坑实录|Hive1\.2\.1数据服务接口5大疑难问题调试与全方位优化方案】
java·hive·spring boot
2601_955759881 小时前
如何识别 Claude API 低价值调用并优化
java
鹿角片ljp2 小时前
Java框架篇:Spring + SpringMVC + SpringBoot + MyBatis深度复习
java·开发语言