CAS(Compare-And-Swap,比较并交换)
                           
天天向上
发布: 2025-07-12 13:21:28

原创
917 人浏览过

CAS(Compare-And-Swap,比较并交换) 是 Java 并发编程中实现无锁(lock-free)线程安全的重要机制,是 java.util.concurrent 包如 AtomicIntegerConcurrentHashMapThreadPoolExecutor 等底层并发类的核心基础。


一、CAS 是什么?

CAS 是一种原子操作指令,它的作用是:如果内存中的值和预期值相同,则将其更新为新值;否则不做任何操作。

基本操作原理:

CAS(V, E, N)

V:内存中的变量(volatile)
E:期望值(Expected)
N:新值(New)

含义:如果 V == E,则 V ← N,否则什么都不做

二、CAS 在 Java 中的实现(Unsafe)

Java 中的 CAS 是通过 sun.misc.Unsafe 类封装的 compareAndSwapInt() / compareAndSwapLong() 等方法实现的,最终调用的是 CPU 提供的原子指令(如 x86 的 CMPXCHG)


三、CAS 示例(以 AtomicInteger 为例)

AtomicInteger count = new AtomicInteger(0);

public void increment() {
    while (true) {
        int oldValue = count.get();
        int newValue = oldValue + 1;
        // 如果旧值没有被其他线程更改,则更新成功
        if (count.compareAndSet(oldValue, newValue)) {
            break;
        }
        // 否则自旋,继续重试
    }
}

compareAndSet() 方法底层就是一个 CAS 原子操作。


四、CAS 的优点

优点说明
✅ 无需加锁提高并发性能,避免上下文切换
✅ 原子性强由 CPU 保证的硬件级原子操作
✅ 高效在竞争不严重的场景下性能优于锁

五、CAS 的三大问题及解决方案

1、ABA 问题

  • 问题: CAS 判断的是值是否相等,如果值从 A → B → A,会误判为没变。
  • 解决: 引入版本号机制,如 AtomicStampedReference
AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 1);

2、自旋开销大

  • 问题: 如果 CAS 一直失败,会不断重试(自旋),浪费 CPU。
  • 解决:
  • 控制重试次数
  • 使用 LongAdder 等分段方式降低冲突
  • 在竞争严重场景用锁替代

3、只能保证单变量原子性

  • 问题: CAS 只能保证一个变量的原子操作
  • 解决:
  • 使用锁保证多个变量的一致性
  • 或使用原子引用(AtomicReference

六、CAS vs 锁(synchronized / ReentrantLock)

对比点CAS锁(synchronized)
原子性保障CPU 指令层面JVM 保证
是否阻塞❌ 非阻塞,自旋✅ 阻塞
性能(低竞争)✅ 高性能较慢(有上下文切换)
性能(高竞争)❌ 自旋浪费资源✅ 线程挂起等待,系统资源少占用
多变量原子性❌ 不支持✅ 支持

七、CAS 使用的类(JDK 并发包)

类名使用 CAS 的字段
AtomicIntegervalue
AtomicReference引用对象
ConcurrentHashMapNode.val、表初始化
ThreadPoolExecutorctl
LongAdder分段累加器控制逻辑

八、CPU 层级实现

  • CAS 的 CPU 指令:CMPXCHG(x86 架构)
  • 原子性保障:通过总线锁或缓存一致性协议(MESI)

九、参考链接


十、总结记忆(口诀)

CAS 三元组,比较换更新;轻量不加锁,三大问题警惕;结合原子类,高效保线程。


更多详细内容请关注其他相关文章!

发表回复 0

Your email address will not be published. Required fields are marked *