CAS 是什么?如果版本号不一致会怎样处理?

1 个回答

  • 辰南
    今朝有酒今朝醉,明日愁来明日愁。
    ## 1. CAS 的概念 CAS 全称 **Compare And Swap**(比较并交换),是一种**无锁的原子操作**,通常由 CPU 提供指令级支持(如 x86 的 `CMPXCHG`)。 **核心思想**: 1. 读取某个变量的**旧值**(期望值 expect) 2. 比较当前内存值和期望值是否相等 3. 如果相等 → 把它更新成新值(update) 4. 如果不相等 → 更新失败,返回 false,调用方自行决定是否重试 在 Java 里,CAS 是 `Unsafe.compareAndSwapXXX` 或 `VarHandle.compareAndSet` 的底层原理,广泛用在 **Atomic 原子类、并发容器、LongAdder、AQS** 等。 ## 2. 版本号(或期望值)不一致的处理 CAS 的版本号本质就是**期望值 expect**(可能是内存中实际值,也可能是附加的版本字段)。 * 如果当前值 == 期望值 → 更新成功 * 如果当前值 ≠ 期望值 → 更新失败,返回 false 常见处理方式: 1. **重试自旋**(最常见) ```java do { oldVal = atomic.get(); newVal = oldVal + 1; } while (!atomic.compareAndSet(oldVal, newVal)); ``` * 一直尝试直到成功(自旋会消耗 CPU,冲突高时可加退避策略) 2. **放弃更新** * 如果失败就直接返回(比如队列竞争时丢弃任务) 3. **重新读取并计算** * 失败后读取最新值,重新计算 update,再 CAS 尝试一次 ## 3. 和版本号相关的“ABA 问题” * 问题:CAS 只判断“值是否相等”,如果值从 **A → B → A**,CAS 会认为没变,可能误更新。 * 解决方法: * **版本戳机制**(类似乐观锁的版本号):`AtomicStampedReference` * **标记位机制**:`AtomicMarkableReference` 示例(AtomicStampedReference): ```java int[] stamp = new int[1]; V value = ref.get(stamp); boolean success = ref.compareAndSet(value, newValue, stamp[0], stamp[0] + 1); ``` 这样就必须**值和版本号都相等**才能成功更新。 ## 4. 一句话总结 CAS 是一种**基于比较和交换的原子操作**,版本号不一致(即期望值和实际值不同)时会**更新失败**,常用**重试自旋或重新读取**来处理;为避免 ABA 问题,可引入**版本戳**。
    发布于 2025-08-13 15:03 •IP属地 黑龙江
    举报
    评论
    收藏