当前位置: 首页 > article >正文

CAS带来的ABA问题以及解决方案

CAS带来的ABA问题

在这里插入图片描述
线程1和线程2同时对变量i = 1 进行操作,线程1对i进行了两次操作,先将i+1 写出,后又进行了i-1并写出,线程2过来读的时候与原来值1仍然是相等的,虽然值仍然相等,但是i的值却发生过改变,期间从1变成2又变成1(ABA问题)。

解决方案

对值的每次操作都进行记录,需要保证是一个原子操作。
在这里插入图片描述
java中使用AtomicMarkableReference或者AtomicStampedReference。
AtomicMarkableReference:使用boolean表示是否修改过。
AtomicStampedReference: 使用int 记录改变的次数(推荐)!

AtomicStampedReference 使用:

class Stu {
    private String name;
    private Integer age;
getter/setter
}

//参数1: 对象 
//参数2:初始版本号
 AtomicStampedReference<Stu> accountBalance = new AtomicStampedReference<>(stu, 0);
 
源码:
public AtomicStampedReference(V var1, int var2) {
    this.pair = AtomicStampedReference.Pair.of(var1, var2);
}
static <T> Pair<T> of(T var0, int var1) {
    return new Pair(var0, var1);  //底层使用Pair对象。
}

private Pair(T var1, int var2) {
    this.reference = var1;  //真实对象
    this.stamp = var2;   //版本号
}
Thread threadA = new Thread(() -> {
            int[] stampHolder = new int[1];
            //获取对象
            Stu stu1 = accountBalance.get(stampHolder);

            //改变的次数
            int currentStamp = stampHolder[0];
            System.out.println("Thread A: 当前年龄 = " + stu1.getAge() + ", 当前版本号= " + currentStamp);

            stu1.setAge(100000);
            boolean success = accountBalance.compareAndSet(stu1, stu1, currentStamp, currentStamp + 1);
            /**
             *源码:
             * 参数1:  期望值
             * 参数2:  新值
             * 参数3: 原有修改次数
             * 参数4: 新修改次数(一般使用原有修改次数+1)
             *    public boolean compareAndSet(V var1, V var2, int var3, int var4) {
             *
             *         //原始对象值  包含对象和修改的次数
             *         Pair var5 = this.pair;
             *         return
             *              var1 == var5.reference  //对象不是同一个(期望值不一样)  就不再进行操作
             *              && var3 == var5.stamp   // 版本号不一样  就不再进行操作
             *              && (var2 == var5.reference && var4 == var5.stamp   //操作对象与原来一样并且操作次数也一样 表示中间的值没有被其他线程修改过,无需继续修改
             *                      ||
             *                  this.casPair(var5, AtomicStampedReference.Pair.of(var2, var4)));  //进行CAS操作
             *     }
             *
             *
             *
             *
             *
             */

            if (success) {
                System.out.println("Thread A: 更新成功,新的年龄 = " + accountBalance.getReference().getAge() + ",新的版本号" + accountBalance.getStamp());
            } else {
                System.out.println("Thread A: 更新失败");
            }
        });

http://www.kler.cn/a/289923.html

相关文章:

  • 【excel】easy excel如何导出动态列
  • 软件测试面试大全(含答案+文档)
  • 如何用WordPress和Shopify提升SEO表现?
  • 机器学习day3-KNN算法、模型调优与选择
  • 使用Matlab建立随机森林
  • Android 配置默认输入法
  • 微小目标检测
  • 排查SQL Server中的内存不足及其他疑难问题
  • 力扣3272.统计好整数的数目
  • Ansible的脚本:playbook
  • 获取4字节数据中比特为 1 的总数的方法
  • 线性代数教材书籍推荐
  • 前端面试:分类算法列一下有多少种应用场景?
  • Automatic Trim Implementation
  • 过滤器Filter(JavaEE有三大组件: servlet filter linstener)
  • Ae关键帧动画基础练习-街道汽车超车
  • Oracle查询优化--分区表建立/普通表转分区表
  • python图像类型分类汇总
  • 代码随想录训练营day35|46. 携带研究材料,416. 分割等和子集
  • 荆州农商行资产质量下行压力不减,参股多家银行均有股权被冻结
  • Find My轮椅|苹果Find My技术与轮椅结合,智能防丢,全球定位
  • Spark框架
  • Nginx: 使用KeepAlived配置实现虚IP在多服务器节点漂移及Nginx高可用原理
  • 12、Flink 流上的确定性之流处理详解
  • Tomcat8版本以上配置自定义400错误页面
  • ElasticSearch-基础操作