CAS - Compare And Swap
特性
- 用于实现乐观锁/自旋锁
- 基于
Unsafe实现 - 只保证了原子性
- 靠硬件实现, 执行 cmpxchg 指令时, 处理器会自动锁定总线
- CAS操作在ARM和x86下的不同实现
存在的问题
- ABA 问题
- A 被改成 B, 然后 B 又被改成 A, 值没变, 但是被别人修改过了
AtomicStampedReference, 增加了stamp版本号, 可以解决
- 循环时间长开销大 (忙等待)
- CAS 经常会用到自旋操作来进行重试
- 只能保证一个共享变量的原子操作
AtomicReference类, 保证引用对象之间的原子性
CAS 自旋
CAS 本身不自旋, 通常情况下, CAS 操作都会采用自旋的方式. 当 CAS 失败时,会重新尝试执行 CAS 操作, 直到操作成功或达到最大重试次数为止.
// Unsafe#getAndAddInt 原子地获取并增加整数值
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
// 以 volatile 方式获取对象 o 在内存偏移量 offset 处的整数值
v = getIntVolatile(o, offset);
} while (!compareAndSwapInt(o, offset, v, v + delta));
// 返回旧值
return v;
}CAS+自旋实现单例
实际工作中不要用这种方法
public class Singleton {
private static final AtomicReference<Singleton> INSTANCE =
new AtomicReference<Singleton>();
private Singleton() {}
public static Singleton getInstance() {
for (;;) {
Singleton singleton = INSTANCE.get();
if (null != singleton) {
return singleton;
}
singleton = new Singleton();
if (INSTANCE.compareAndSet(null, singleton)) {
return singleton;
}
}
}
}