什么是CAS?
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));// getDeclaredField是可以获取一个类的所有字段.
// getField只能获取类的public 字段.
} catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);当前对象,内存偏移量
}
================================================================================
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
Unsafe是CAS的核心类,本来java方法无法直接访问底层系统,需要通过调用Native方法才可以。但是java给自己留了一个后门,基于Unsafe类可以直接操作特定内存的数据。其内部方法可以像C的指针一样直接操作内存,且CAS操作依赖于Unsafe类中的方法。
unsafe根据内存偏移地址valueOffset获取数据
变量使用volatile修饰保证了多线程之间的内存可见性(private volatile int value;)
CAS: 它是一条CPU并发原语,调用Unsafe中的CAS方法,JVM会帮我们实现出CAS的汇编指令。这是一种完全依赖于硬件的功能,通过它实现了原子操作。由于CAS是一种系统原语属于操作系统用语范畴,是由若干条指令组成的,用于完成某一个功能的过程。且原语的执行是连续不可被中断的,所以不会造成数据不一致问题。
public final int getAndAddInt(Object var1, long var2, int var4) {
// var对应this,即atomic类本身
// valueOffset对应 var2,当前值的内存偏移量
int var5;
do {
var5 = this.getIntVolatile(var1, var2);// 获取当前var1对象的 var2地址值对应数值
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
不同则继续取值比较,直至相同(自旋锁思想)
CAS缺点:
1.循环时间长性能开销大
2.只能保证一个共享变量的原子操作
3.ABA问题
ABA问题:
不要想的太难,就按字面理解就可以。在某一阶段A变为了B,但是最后又变回了A。系统判断为A一直为A没有改动,但是再系统不知情的一段时间内A是有过变化的。
解决ABA:
AtomicStampedReference