深入理解CAS,解决ABA问题

CAS

CAS是英文单词CompareAndSwap的缩写,中文意思是:比较并替换。CAS需要有3个操作数:内存地址V,旧的预期值A,即将要更新的目标值B。

CAS指令执行时,当且仅当内存地址V的值与预期值A相等时,将内存地址V的值修改为B,否则就什么都不做。整个比较并替换的操作是一个原子操作。

代码演示:

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

      //期望、更新
      //public final boolean compareAndSet(int expect,int update)
      //如果我期望的值达到了,那么就更新,否则就不更新,CAS是CPU的并发原语
        System.out.println(atomicInteger.compareAndSet(2020, 2021));
        System.out.println(atomicInteger.get());

        atomicInteger.getAndIncrement();
        System.out.println(atomicInteger.compareAndSet(2020, 2021));
        System.out.println(atomicInteger.get());
        }
    }
//运行结果
//2021
//false
//2021

unsafe类
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
CAS:比较当前工作内存中的值和主内存中的值,如果这个值时期望的,那么则执行操作,否则就一直循环!
缺点:

  1. 循环会耗时
  2. 一次性只能保证一个共享变量的原子性
  3. ABA问题

CAS:ABA问题(狸猫换太子)
在这里插入图片描述

public class CASDemo {
   // CAS  compareAndSet : 比较并交换!
    public static void main(String[] args) {
      AtomicInteger atomicInteger = new AtomicInteger(2020);

      //期望、更新
      //public final boolean compareAndSet(int expect,int update)
      //如果我期望的值达到了,那么就更新,否则就不更新,CAS是CPU的并发原语
      //==============捣乱的线程===================
        System.out.println(atomicInteger.compareAndSet(2020, 2021));
        System.out.println(atomicInteger.get());

       System.out.println(atomicInteger.compareAndSet(2021, 2020));
        System.out.println(atomicInteger.get());

        //==============期望的线程===================
        System.out.println(atomicInteger.compareAndSet(2020, 6666));
        System.out.println(atomicInteger.get());
    }
}

在这里插入图片描述
解决ABA问题,引入原子引用
带版本号的原子操作
在这里插入图片描述
下面代码里注意我们用的是Integer,所以数字在-128~127之间,不能用上面例子里的2020,2021,666数字。
在这里插入图片描述

public class CASDemo {

    //AtomicStampedReference 注意,如果泛型是一个包装类,注意对象的引用问题

    // 正常在业务操作,这里面比较的都是一个个对象
    static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(1,1);

    // CAS  compareAndSet : 比较并交换!
    public static void main(String[] args) {

        new Thread(()->{
            int stamp = atomicStampedReference.getStamp(); // 获得版本号
            System.out.println("a1=>"+stamp);

            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            Lock lock = new ReentrantLock(true);

            atomicStampedReference.compareAndSet(1, 2,
                    atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);

            System.out.println("a2=>"+atomicStampedReference.getStamp());


            System.out.println(atomicStampedReference.compareAndSet(2, 1,
                    atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));

            System.out.println("a3=>"+atomicStampedReference.getStamp());

        },"a").start();


        // 乐观锁的原理相同!
        new Thread(()->{
            int stamp = atomicStampedReference.getStamp(); // 获得版本号
            System.out.println("b1=>"+stamp);

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(atomicStampedReference.compareAndSet(1, 6,
                    stamp, stamp + 1));

            System.out.println("b2=>"+atomicStampedReference.getStamp());

        },"b").start();

    }
}

在这里插入图片描述
本文为学习狂神说的JUC课程做的笔记,课程地址:https://www.bilibili.com/video/BV1B7411L7tE?p=32

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值