惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 叶小钗
爱范儿
爱范儿
WordPress大学
WordPress大学
Last Week in AI
Last Week in AI
博客园 - 聂微东
雷峰网
雷峰网
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 三生石上(FineUI控件)
T
Tailwind CSS Blog
博客园 - Franky
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园_首页
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 司徒正美
月光博客
月光博客
大猫的无限游戏
大猫的无限游戏
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The Cloudflare Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
人人都是产品经理
人人都是产品经理
宝玉的分享
宝玉的分享
罗磊的独立博客
Jina AI
Jina AI

博客园 - 野鹤闲人

ubantu 耳机调试 keepalived+nginx msg广播到同一个group中,怎么保证所有consumer都消费到,Rocketmq和rabbitmq 分别是怎么做的 mysql优化语句时,关注哪几列 extra要关注吗 CountDownLatch/CyclicBarrier 区别 机器缩容要注意哪些问题 IO模型有哪几种 ConcurrentSkipListMap 并发安全实现 TreeMap hive 小文件优化 redis缓存雪崩问题解决 docker的常用命令 k8s的常用组件,和命令 mysql B+树 如果有3层,能保存多少数据 如何保证rabbitmq或kafka 消息不丢失,从生产到消费端全过程 java排查工具 JAVA 强软弱虚引用 git Spring 事务失效
CAS原理
野鹤闲人 · 2026-01-07 · via 博客园 - 野鹤闲人

深入理解 CAS 的核心原理,以及它在多线程场景下的工作机制、优缺点和实际应用,我会从基础概念到底层实现,用通俗易懂的方式帮你讲清楚。

CAS 核心原理

CAS 是 Compare-And-Swap(比较并交换) 的缩写,是一种无锁的原子操作机制,也是实现并发编程的核心思想之一。它的核心目标是:在不使用锁的情况下,保证多线程对共享变量操作的原子性。

1. CAS 的基本逻辑

CAS 操作涉及三个核心参数:

  • V:要修改的共享变量(内存地址)
  • A:预期值(线程读取到的变量当前值)
  • B:新值(线程想要把变量改成的值)

CAS 的执行流程可以概括为:

线程在更新变量 V 时,先对比 V 的当前值是否等于自己之前读取的预期值 A

  • 如果相等,说明没有其他线程修改过这个变量,就把 V 的值更新为新值 B,返回操作成功;
  • 如果不相等,说明其他线程已经修改过这个变量,当前线程不做更新,返回操作失败(线程可选择重试、放弃或执行其他逻辑)。

这个对比 + 交换的过程是CPU 级别的原子指令(如 x86 架构的 cmpxchg 指令),由硬件保证原子性,无需加锁。

2. 通俗举例(理解 CAS 逻辑)

假设两个线程(线程 1、线程 2)要对共享变量 j=0 执行加 1 操作,用 CAS 实现的过程:

  1. 线程 1 读取 j 的值为 0(预期值 A=0),准备更新为 1(新值 B=1);
  2. 线程 1 执行 CAS:对比内存中 j 的值是否等于 0 → 是,将 j 改为 1,操作成功;
  3. 线程 2 也读取 j 的值为 0(预期值 A=0),准备更新为 1(新值 B=1);
  4. 线程 2 执行 CAS:对比内存中 j 的值(此时已被线程 1 改为 1)≠ 预期值 0 → 操作失败;
  5. 线程 2 可选择自旋重试:重新读取 j 的值(现在是 1),再执行 CAS 把 j 改为 2

3. Java 中的 CAS 实现(以 AtomicInteger 为例)

Java 中 java.util.concurrent.atomic 包下的原子类(如 AtomicInteger)就是基于 CAS 实现的,核心依赖 Unsafe 类(提供底层内存操作)。

核心代码示例(简化版):

public class AtomicInteger extends Number implements java.io.Serializable {
    // 共享变量(volatile 保证可见性)
    private volatile int value;
    // Unsafe 类(JDK 内部类,提供底层 CAS 操作)
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset; // value 变量的内存地址偏移量

    static {
        try {
            // 获取 value 变量在内存中的偏移量
            valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

    // 原子加1操作(核心 CAS 逻辑)
    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }

    // Unsafe 的 getAndAddInt 方法底层逻辑(简化)
    // var1:当前对象(AtomicInteger 实例)
    // var2:value 变量的内存偏移量
    // var4:要增加的值(如1)
    public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            // 1. 读取当前内存中的值(预期值 A)
            var5 = this.getIntVolatile(var1, var2);
            // 2. 执行 CAS:对比内存值是否等于 var5,是则更新为 var5+var4
            //    循环直到 CAS 成功(自旋)
        } while (!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
        return var5;
    }
}

关键说明:

  • valuevolatile 修饰,保证多线程间的可见性(一个线程修改后,其他线程能立即看到最新值);
  • compareAndSwapInt 是 native 方法,底层调用 CPU 原子指令,保证对比 + 交换的原子性;
  • 失败时通过 do-while 循环自旋重试,直到 CAS 成功。

4. CAS 的优缺点

优点
  • 无锁开销:无需加锁 / 解锁,避免了线程上下文切换、锁等待的性能损耗;
  • 原子性:由硬件指令保证,比锁更高效(尤其高并发低冲突场景);
  • 非阻塞:线程不会被挂起,失败后可重试或放弃,响应性更好。
缺点
  • ABA 问题: 核心问题:变量值从 A 改为 B,又改回 A,CAS 会认为变量未被修改,导致逻辑错误。 解决方案:使用版本号 / 时间戳(如 AtomicStampedReference),把 “值 + 版本号” 作为对比依据。
  • 自旋开销: 高并发高冲突场景下,线程会一直自旋重试,占用 CPU 资源(可限制重试次数或改用锁)。
  • 只能保证单一变量的原子性: CAS 只能操作单个变量,如果是多变量复合操作(如 j = a + b),无法保证原子性,仍需用锁。

5. CAS vs 锁(核心区别)

特性CAS(无锁)synchronized/ReentrantLock(有锁)
核心机制 硬件原子指令 + 自旋 操作系统内核态锁(阻塞 / 唤醒线程)
性能 低冲突时极高,高冲突时下降 低冲突时略差,高冲突时更稳定
适用场景 单一变量原子操作 复合操作、多变量操作
问题 ABA、自旋开销 死锁、上下文切换开销

总结

  1. CAS 是硬件级别的原子操作,通过 “比较预期值 - 交换新值” 实现无锁原子更新,核心参数是内存地址 V、预期值 A、新值 B;
  2. Java 中 AtomicInteger 等原子类基于 CAS 实现,结合 volatile 保证可见性;
  3. CAS 优点是无锁高效,缺点是存在 ABA 问题、自旋开销,且仅适用于单一变量操作;
  4. 实际开发中,单一变量优先用 CAS(Atomic 类),复合操作优先用锁。