什么是CAS
(compare and swap)比较并交换,是cpu的一个原子指令,不存在线程安全问题
CAS的操作步骤
- 记录内存中要修改的旧值,
- 产生要使用的新值,
- 对比内存中的值是否跟记录的旧值一致,
- 如果一致使用新值覆盖,如果不一致做自旋操作
源代码
//创建一个原子类,并递增加一
AtomicInteger atomicInteger = new AtomicInteger();
atomicInteger.incrementAndGet();
/**
* Atomically increments by one the current value.
*
* @return the updated value
*/
public final int incrementAndGet() {
//通过unsafe类实现原子操作加一
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
//获取内存中的值
var5 = this.getIntVolatile(var1, var2);
//通过c来实现比较并赋值(实现内存中加一)
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
//返回内存中的老值
return var5;
}
ABA问题
ABA问题是指CAS在与记录的旧值比较的内存中的值发生的改变,最终又改成了原来的值。对比依然能通过,但是值已经发生了改变;例如:记录的旧值为1,记录后内存中的1改成了2,后来又改成了1,在最后的对比时虽然值发生了变化,但是依然能通过 解决办法,记录旧值的同时增加一个版本号,在对比旧值的同时对比版本号
import java.util.concurrent.atomic.AtomicStampedReference;
public class ABASolution {
public static void main(String[] args) {
// 初始值为100,版本号为0
AtomicStampedReference<Integer> atomicStampedRef = new AtomicStampedReference<>(100, 0);
int stamp = atomicStampedRef.getStamp();
int value = atomicStampedRef.getReference();
// 模拟一个ABA问题
boolean success = atomicStampedRef.compareAndSet(value, value + 10, stamp, stamp + 1);
if (!success) {
System.out.println("ABA problem detected!");
}
}
}