CAS理解及ABA解决方案

CAS(compareAndSet:比较并交换)

CAS是cpu并发原语,理解步骤如下:

  1. 使用java.util.concurrent.atomic包下的原子类
  2. 原子类的底层是使用unsafe(java的后门,通过这个类来操作内存)并计算出内存偏移量,value使用volatile注释
    在这里插入图片描述
  3. 用getAndIncrement()为例,他传的参为: 当前对象,和内存偏移量,和数字1
    在这里插入图片描述
  4. 从下图可以看出,他根据当前对象和内存偏移量计算出当真实内存位置,然后将该位置加1(自旋锁
    在这里插入图片描述
    cas计算方式
 public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(2020);
        //如果达到期望值,就更新,否则不更新
        boolean b = atomicInteger.compareAndSet(2020, 2021);
        System.out.println(atomicInteger.get());
    }

总结

  1. 比较当前工作内存中的值和主内存中的值,如果这个值是期望的那么则执行操作!如果不是就一直循环
  2. java无法操作内存
  3. java可以调用c++ ( native)
  4. c++可以操作内存
  5. unsafe:java的后门,通过这个类来操作内存

缺点

  1. 循环会耗时
  2. 一次性只能保证一个共享变量的原子性
  3. ABA问题
    CAS:ABA问题(狸猫换太子)
    多个线程操作同一个变量,其中一个线程操作过这个变量,另一个线程并不知情。
    代码如:
   public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(2020);
        //如果达到期望值,就更新,否则不更新
        boolean b = atomicInteger.compareAndSet(2020, 2021);
        System.out.println(atomicInteger.get());
        boolean c = atomicInteger.compareAndSet(2021, 2020);
        System.out.println(atomicInteger.get());
        boolean d = atomicInteger.compareAndSet(2020, 2222);
        System.out.println(atomicInteger.get());
    }

解决ABA问题:原子引用(使用更改后会有版本号)

代码:

//注意使用integer不能使用-128~127之外的数
    public static void main(String[] args) {
//        AtomicInteger atomicInteger = new AtomicInteger(2020);
        AtomicStampedReference<Integer> atomicInteger = new AtomicStampedReference<>(1,1);
        new Thread(()->{
            int stamp = atomicInteger.getStamp();//获得版本号
            System.out.println("a1=>"+stamp);
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(atomicInteger.compareAndSet(1, 2,
                    atomicInteger.getStamp(), atomicInteger.getStamp() + 1));

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

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

            System.out.println("a3=>"+atomicInteger.getStamp());
        },"a").start();
        new Thread(()->{
            int stamp = atomicInteger.getStamp();//获得版本号
            System.out.println("b1=>"+stamp);
            try {
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(atomicInteger.compareAndSet(1, 6,
                    stamp, stamp + 1));
            System.out.println("b2=>"+atomicInteger.getStamp());
        },"b").start();
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值