java并发编程CAS理解

1.CAS是什么

CAS就是Compare and Swap,意思是比较并交换,CAS使用了3个值,V内存值,A预期值,B要更新的值,判断内存值是否等于预期值,如果相等则将B更新为内存值。在Java中,使用的是Unsafe类来实现CAS。

2.CAS实现

  
   public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }

以AtomicInteger类为例,其中有方法getAndIncrement,调用了unsafe的getAndAddInt方法,this是当前对象,valueOffset是value的内存地址。

  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类getAndAddInt方法中,var1是传过来的AtomicInteger对象,var2是该对象的地址,var4是操作的数值,var5是内存值,通过var1和var2从内存中获取,由于内存值是由volatile修饰的,所以是线程可见。
执行this.compareAndSwapInt(var1, var2, var5, var5 + var4),如果线程没有修改AtomicInteger的值,那么通过var1和var2获取的值与var5相等,则更新AtomicInteger的value值,并且返回true,结束循环。
如果线程修改了AtomicInteger的值,那么通过var1和var2获取的值与var5不相等,返回false,进行下一次循环,再次进入do while循环时,重新执行var5 = this.getIntVolatile(var1, var2);方法更新内存值,执行this.compareAndSwapInt(var1, var2, var5, var5 + var4),如果线程没有修改AtomicInteger的值,那么通过var1和var2获取的值与var5相等,则更新AtomicInteger的value值,并且返回true,结束循环。
上述过程实现了原子操作

3.CAS存在的问题

1.ABA问题
CAS需要在操作值的时候检查下值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,但是实际上却变化了。这就是CAS的ABA问题。常见的解决思路是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就会变成1A-2B-3A。JDK从1.5开始提供了AtomicStampedReference类来解决ABA问题。这个类的compareAndSet方法作用是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。

2.循环时间长开销大
上面我们说过如果CAS不成功,则会原地自旋(一直 do while),如果长时间自旋会给CPU带来非常大的执行开销。

3.只能保证一个共享变量的原子操作
对一个共享变量执行操作时,CAS能够保证原子操作,但是对多个共享变量操作时,CAS是无法保证操作的原子性的。

你可能感兴趣的:(java并发编程)