CAS是什么?AtomicInteger为什么使用CAS? AtomicInteger的底层原理是什么?

1、CAS   即 Compare -And- Swap   比较并交换;

2、 通过AtomicInteger.compareAndSet();方法能够解决多线程模式下i++计算结果出现的数据不一致的问题。

/**
 * @program: mybatis
 * @description: CAS
 * @author: Miller.FAN
 * @create: 2019-11-11 18:24
 **/
public class CASDome {

    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(5);
        System.out.println(atomicInteger.compareAndSet(5,2018)+"/t current data " + atomicInteger.get());
    }
}

3、AtomicInteger.compareAndSet()底层实现是什么?

    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

4、unsafe.compareAndSwapInt(this, valueOffset, expect, update)的底层是什么样的?

    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类种的一个方法,Unsafe中的方法都是直接调用操作系统底层资源执行相应的任务,即操作系统底层原语,不容许被打断,不会造成所谓的数据不一致的问题。
var5 = this.getIntVolatile(var1, var2);中var1指当前对象,var2内存偏移地址。结果var5就是获得的内存中的数据。
do {
    var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));    // 拿一下主内存地址中的值与自己保存的快照对比,如果一致就修改,如果不一致放弃修改,再做一次var5 = this.getIntVolatile(var1, var2);,直到主内存中的值与自己的快照值一直,海海皮皮的进行修改跳出循环,return var5+1;

5、为什么不直接使用Synchronized,而使用CAS呢?

杀鸡焉用牛刀?Synchronized是重锁,并发效率低。

6、CAS的缺点是什么?

循环时间长,CPU开销大。只能保证一个共享变量的一致性操作。不可避免的ABA问题。

7、ABA问题的演示和解决

public class AutmicRefence {
    
    static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
    static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100,1);

    public static void main(String[] args) {

        //ABA问题的演示
        new Thread(()-> {
            atomicReference.compareAndSet(100,101);
            atomicReference.compareAndSet(101,100);
        },"t1 ").start();

        new Thread(()-> {
            try{
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("current thread :" + atomicReference.compareAndSet(100,2049) + "/t current value: "+atomicReference.get());
        },"t2").start();

        //ABA问题的解决
        new Thread(()-> {
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "/t 第一次的本版号" + stamp);
            try{
                TimeUnit.SECONDS.sleep(1);
            } catch (Exception e) {
                e.printStackTrace();
            }
            atomicStampedReference.compareAndSet(100,101,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
            System.out.println(Thread.currentThread().getName() + "/t 第二次的本版号" + atomicStampedReference.getStamp());
            atomicStampedReference.compareAndSet(101,100,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
            System.out.println(Thread.currentThread().getName() + "/t 第三次的本版号" + atomicStampedReference.getStamp());
        },"t3 ").start();

        new Thread(()-> {
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "/t 第一次的本版号" + stamp);
            try{
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
                e.printStackTrace();
            }
            boolean ret = atomicStampedReference.compareAndSet(100,101,stamp,stamp+1);
            System.out.println(Thread.currentThread().getName() + "/t 第二次的本版号" + atomicStampedReference.getStamp());
            System.out.println("修改成功否?" + ret);
            System.out.println("当前值是多少?" + atomicStampedReference.getReference());
        },"t4 ").start();
    }

}
发布了85 篇原创文章 · 获赞 21 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_41670928/article/details/103022010