Java面试题——CAS(compareAndSet)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_42237752/article/details/102584525

CAS是什么?

就是比较并交换
之前咱们学过了jmm模型(没有学过的同学请点击连接JMM和JVM内存模型),从中可以知道每个线程都会将主内存中的数据拷贝到自己内存中进行运算,而CAS则是比较当前工作内存中的值与主内存中的值,如果相同则执行规定操作,否则继续比较直到主内存和工作内存中的值一致为止
测试代码:


/**
 * @author shihangqi
 * @date 2019/10/15 - 11:00
 *
 * 1   CAS是什么?
 *     比较并交换
 */
public class CASDemo {

    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(5);

        System.out.println(atomicInteger.compareAndSet(5, 2019)+"\t current data"+atomicInteger.get());
        System.out.println(atomicInteger.compareAndSet(5, 1024)+"\t current data"+atomicInteger.get());
    }
}

CAS底层原理

1、核心是Unsafe类(在jdk中rt.jar中的sun.misc下的Unsafe类),由于Java方法无法直接访问底层系统,需要通过本地(native)方法来访问,Unsafe相当于一个后门,基于该类可以直接操作特定内存的数据。换句话说就是CAS其实是直接操作的地址中的内容。

CAS并发原语体现在JAVA语言中就是sun.misc.Unsafe类中的各个方法。调用UnSafe类中的CAS方法,JVM会帮我们实现出CAS汇编指令。这是一种完全依赖于硬件的功能,通过它实现了原子操作。再次强调,由于CAS是一种系统原语,原语属于操作系统用语范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被打断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题。
这是getAndIncrement方法的源码
在这里插入图片描述
这是unsafe中的getAndAddInt方法源码,核心思想是这个dowhile语句

    /**
     * var1是对象值
     * var2是地址偏移量
     * var4是自增值
     * var5是获取到的主内存中的值
     */
    
    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));//根据获取主内存值再与刚才获取的var5进行比较,如果相同则进行var5+var4,否则重新进行循环

        return var5;
    }

在哪应用

我们知道AtomicInteger.getAndIncrement()是可以进行原子性的自增操作,那么atomic类型如何实现的原子性呢,就是利用的CAS原理
例子:CAS有三个操作数,内存值V,旧的预期值A,要修改的更新值B。当且仅当预期值A和内存值V修改为B,否则什么都不做

CAS的缺点

  1. CAS底层使用了do while操作,循环时间长开销大。
  2. 只能保证一个共享变量的原子操作。
  3. 引出来ABA问题

猜你喜欢

转载自blog.csdn.net/weixin_42237752/article/details/102584525