J.U.C - CAS 操作 ABA 问题及解决方案

CAS 操作 ABA 问题及解决方案

注意: 本文是博主自己的拙见,如发现描述或理解问题,可以联系博主随时修改。

在上一篇文章中 《一篇文章看懂CAS》 描述到了 CAS 的工作原理,那么这篇文章来说一下 CAS 存在的 ABA 问题及如何解决

什么是 ABA 问题 ?

主内存中变量为 10,正常线程 t1 线程和错误线程 t2 线程同时 -5 那么 t1t2 期望的值都是 5,正常情况下只有 t1 才会正确执行,t2 会更新失败
在这里插入图片描述

  • 当线程 t1, t2 同时启动,并将主内存中的变量拷贝到自己工作空间完成了递减操作,假设 t2 线程在此时进入了阻塞状态,t1更新成功后返回
    在这里插入图片描述
  • 此时 新进入一条线程 t3 要对主内存中变量 +5 操作, 而 t2 线程依然处于阻塞状态,主内存中的变量变成了 10
    在这里插入图片描述
  • t3 执行完毕后 t2 线程恢复,去更新主内存中的内容,发现旧值和主内存中的值一致,于是将主内存中的值更新为 5
    在这里插入图片描述
    根据上面的情况可以看出,如果没有错误线程 t2 的更新成功,那么正确值应该是 10,但是由于 t2 更新成功了,导致最终结果为 5 ,由此可见,如果在现实生活中发生这样的问题,是不可行的,对于上面这种情况又该如何解决。

ABA 问题如何避免 ?

通过上述对 ABA 问题的阐述,发现最终的问题在于不同线程在更新变量的时候操作的都是不同版本的数据,那么我们是不是可以直接新增一个数据的版本号对数据进行控制,在更新数据之前对比一下版本号是否一致,就能保证数据准确性了。没错,思路就是这样子的。在 JDK 中提供了基于版本号的原子操作类

public class CasVersionAbaDemo {

   static AtomicReference<Integer> a = new AtomicReference<>(0);

   public static synchronized void increment (){
       a.compareAndSet(a.get(), a.get() + 1);
   }

   public static void main(String[] args) throws InterruptedException {
       for (int i = 0; i < 1000; i++) {
           new Thread(CasVersionAbaDemo::increment).start();
       }
       Thread.sleep(4000);

       System.out.println(a.get());
   }
}

参考:什么是CAS机制?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值