深入理解CAS

HeJin大约 1 分钟JavaJUC并发编程

什么是CAS

atomicInteger.compareAndSet() 比较并更新。如果期望的值达到了,那么就更新,否则不更新。

/**
 * Atomically sets the value to the given updated value
 * if the current value {@code ==} the expected value.
 *
 * @param expect the expected value
 * @param update the new value
 * @return {@code true} if successful. False return indicates that
 * the actual value was not equal to the expected value.
 */
public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

代码实践

public class CasDemo {
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(2021);
        // 如果期望的值达到了,那么就更新,否则不更新
        System.out.println(atomicInteger.compareAndSet(2021, 2022));
        atomicInteger.compareAndSet(2021, 2022);
        System.out.println(atomicInteger.get());
        System.out.println(atomicInteger.compareAndSet(2021, 2022));
        System.out.println(atomicInteger.get());
    }
}

结果:

true
2022
false
2022
    
Process finished with exit code 0

CAS是CPU的并发原语。

AtomicInteger加1的原理

AtomicInteger atomicInteger = new AtomicInteger(2021);
atomicInteger.getAndIncrement();
image-20210325164336438
image-20210325164336438

Java无法操作内存,Java可以调用C++(native),C++可以操作内存。Unsafe类相当于Java的后门,可以通过这个类操作内存。

image-20210325164258615
image-20210325164258615

Unsafe类里的getAndAddInt方法

image-20210325164210376
image-20210325164210376
// AtomicInteger类
public final int getAndIncrement() {
    return unsafe.getAndAddInt(this, valueOffset, 1);
}
// UnSafe类
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;
}

var1相当于数组对象a,var2相当于a中的角标i,因为var5==a[i] ,var5+1就是a[i]+1,即实现了getAndIncrement()。

总结

比较当前工作内存中的值和主内存中的值,如果这个值是期望的,那么则执行操作。否则不执行。如果不是就一直循环。

缺点

  • 循环会耗时。
  • 一次性只能保证一个共享变量的原子性。
  • 存在ABA问题。