CAS能保证原子性,顺序性,可见性么,原理是什么?
CAS(Compare-And-Swap)操作能保证原子性,但不直接保证顺序性和可见性。它需要配合其他机制(如内存屏障或volatile
变量)才能实现完整的并发安全。其核心原理依赖于硬件指令和底层内存模型的支持。以下是详细分析:
1. 原子性(Atomicity)
-
保证:是
-
原理:
CAS 是一个硬件级原子指令(如 x86 的CMPXCHG
),由 CPU 直接支持。该操作包含“读取-比较-写入”三个步骤,但在执行时会被合并为一个不可中断的单一指令,确保在多核环境下:-
读取内存值。
-
比较当前值是否等于预期值。
-
仅当比较成功时写入新值。
若其他线程中途修改了内存值,CAS 会失败(返回false
),整个过程无中间状态。
-
2. 可见性(Visibility)
-
不直接保证,但通常通过底层机制间接实现。
-
原理:
-
CAS 操作本身会触发 CPU 缓存一致性协议(如 MESI),强制其他核心的缓存失效,确保读取的是最新内存值。
-
在 Java 中,CAS 通常通过
Unsafe
类实现,底层调用 JVM 的cmpxchg
指令,隐式插入内存屏障(如lock
前缀指令),刷新写缓冲、使缓存失效,实现写操作的全局可见。 -
重要前提:
CAS 操作的目标变量必须声明为volatile
(如AtomicInteger
内部使用volatile int value
)。否则,其他线程可能看不到 CAS 修改后的值。
-
3. 顺序性(Ordering)
-
不直接保证,但可通过内存屏障控制。
-
原理:
-
CAS 的底层指令(如 x86 的
LOCK CMPXCHG
)自带 内存屏障效果:-
写屏障:确保 CAS 之前的写操作对后续其他线程可见。
-
读屏障:确保 CAS 之后能读取到最新值。
-
-
局限性:
CAS 仅保证自身操作的原子性和部分内存顺序,不保证非 CAS 操作的顺序(如a=1; b=2;
仍可能被重排序)。
在 Java 中,Atomic
类的方法(如getAndIncrement()
)通过组合volatile
读写 + CAS,利用volatile
的happens-before
规则保证顺序性。
-
CAS 底层实现原理
以 Java 的 Unsafe.compareAndSwapInt()
为例:
// 伪代码:Unsafe.compareAndSwapInt
public final native boolean compareAndSwapInt(
Object obj, long offset, int expected, int newValue
);
// 底层 x86 指令实现(JVM 内联汇编):
lock cmpxchg DWORD PTR [obj+offset], newValue
-
lock
前缀:
锁定内存总线(或缓存行),确保操作独占内存,触发缓存一致性协议,隐式加入内存屏障。 -
cmpxchg
:
比较[obj+offset]
处的值是否等于expected
,若相等则写入newValue
。
CAS 的典型应用
// Java AtomicInteger 的自增实现
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, VALUE_OFFSET, 1);
}
// Unsafe.getAndAddInt
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset); // volatile 读,保证可见性
} while (!compareAndSwapInt(o, offset, v, v + delta)); // CAS 重试
return v;
}
-
getIntVolatile
保证读取最新值(可见性)。 -
CAS 确保原子更新。
-
循环重试解决竞争冲突。
CAS 的局限性
-
ABA 问题:
值从 A 变 B 再变回 A,CAS 误判未修改。
解决方案:使用版本号(如AtomicStampedReference
)。 -
自旋开销:
高竞争下长时间循环消耗 CPU。 -
单变量限制:
只能保护单个变量,复合操作需锁。
总结
特性 | CAS 是否保证 | 依赖条件 |
---|---|---|
原子性 | ✅ 是 | 硬件指令支持 |
可见性 | ⚠️ 间接保证 | 需配合 volatile 或内存屏障 |
顺序性 | ⚠️ 间接保证 | 需配合内存屏障或 volatile |
关键结论:
CAS 通过硬件指令保证原子性,其内存屏障效果和缓存一致性协议间接提供可见性与部分顺序性,但完整并发安全需依赖
volatile
或显式同步(如synchronized
)。在无竞争时性能优于锁,高竞争时需谨慎使用。