ABA问题的解决

2023-11-01

什么是ABA问题?

ABA问题是发生在CAS过程当中的下面以一个例子来表示:

假如有两个线程A,B,两个线程都从主内存中获取了某个对象的值为value1,当进行CAS的时候A首先把value1更换成了value2。因为线程B可能没有CPU资源调度导致行动缓慢,这个时候A又再次的将value2变量改变回了value1。
当B线程有CPU执行权的时候进行CAS的时候,原来自己获得的是value1主内存里面的还是value1就进行更新自己要更新的值。但是value1已经被A线程修改过,虽然可以修改成功,但这个违背了CAS的初衷,这就是ABA问题。简单的一句话:狸猫换太子:先把太子换成狸猫,又把狸猫换回了太子。
下面用一串代码来表示ABA问题


public class ABADemo {

   static  AtomicReference<Integer> atomicReference = new AtomicReference<>(100);

    public static void main(String[] args) {
              System.out.println("==========ABA问题的产生============");
        new Thread(()->{
            System.out.println(atomicReference.compareAndSet(100,101)+Thread.currentThread().getName());
            System.out.println(atomicReference.compareAndSet(101,100)+Thread.currentThread().getName());
         },String.valueOf("AA")).start();

        new Thread(()->{
            try{
                TimeUnit.SECONDS.sleep(1);
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            System.out.println(atomicReference.compareAndSet(100,200)+Thread.currentThread().getName());

         },String.valueOf("BB")).start();
    }
}

结果:
在这里插入图片描述

ABA问题的解决

解决思路:难点在于B线程不知道那个value1是不是已经被动过,那么我们可以在value1对象上加上一个版本,取value1对象的时候连版本号也取出来,当value1对象每次被修改的时候都将value1的版本号进行改变,那样就可以知道value1对象有没有被修改过。
可以使用带版本号的原子引用
下面用一个代码的demo来演示·一下:


public class ABADemo {

    static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100,1);
    public static void main(String[] args) {
        System.out.println("===========ABA问题的解决============");

        new Thread(()->{
            int stamped = atomicStampedReference.getStamp();
            System.out.println("初始版本号为"+stamped);
            try{
                TimeUnit.SECONDS.sleep(1);
                System.out.println(atomicStampedReference.compareAndSet(100,101,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1));
                System.out.println("第一次修改后版本号为"+atomicStampedReference.getStamp());
                System.out.println("第一次修改后当前值"+atomicStampedReference.getReference());
                System.out.println(atomicStampedReference.compareAndSet(101,100,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1));
                System.out.println("第二次修改后版本号为"+atomicStampedReference.getStamp());
                System.out.println("第一次修改后当前值"+atomicStampedReference.getReference());
            }catch(InterruptedException e){
                e.printStackTrace();
            }

         },String.valueOf("AA")).start();

        new Thread(()->{
            int stamped = atomicStampedReference.getStamp();
            System.out.println("初始版本号为"+stamped);
            try{
                TimeUnit.SECONDS.sleep(2);
                System.out.println(atomicStampedReference.compareAndSet(100,2022,stamped,stamped+1));

            }catch(InterruptedException e){
                e.printStackTrace();
            }


         },String.valueOf("BB")).start();

    }
}

结果:
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ABA问题的解决 的相关文章

随机推荐

  • 环境配置相关

    anaconda pip无法识别 win10安装了Anaconda之后 未设置环境变量 想用pip命令导入第三方库 在anaconda文件夹下打开命令窗口 输入pip install tensorflow 报错如下 pip 无法将 pip
  • NFT数字藏品平台开发——如何快速搭建搭建数字藏品平台

    2021年可以称为元宇宙年 随着元宇宙概念的兴起 好多人都在关心我们是否可以成功构建元宇宙 显然是可以实现的 2022年年初 NFT在国内的热潮兴起 国内也称之为数字藏品 NFT由于具有不可置换 不可分割的特性 很快在国内掀起一热潮 西西弗
  • 线程间的通讯

    一 为什么需要线程通讯 线程是操作系统调度的最小单位 有自己的栈空间 可以按照既定的代码逐步的执行 但是如果每个线程间都孤立的运行 那就会造资源浪费 所以在现实中 我们需要这些线程间可以按照指定的规则共同完成一件任务 所以这些线程之间就需要
  • LoadRunner--并发测试(多用户)

    并发测试 多用户进行并发测试 即在同一时刻同时进行某种操作 1 何时使用集合点 并发测试时使用 2 并发测试的两个条件 1 脚本中加入集合点 在事务开始之前添加集合点 则所有虚拟用户执行到集合点时停止 等待并发 2 控制台中设置集合点策略设
  • TypeScript 枚举(enum)

    枚举定义 枚举通过enum关键字来定义 使用枚举我们可以定义一些有名字的数字常量 enum Direction Up 1 Down Left Right 枚举成员 一个枚举类型可以包含零个或多个枚举成员 枚举成员具有一个数字值 它可以是常数
  • UE4 碰撞射线检测

    默认 TraceTypeQuery1 Visibility 默认 TraceTypeQuery2 Camera void ATraceCharacter traceByChannel 获取该组件的拥有者 AActor MyOwner Get
  • 快速安装Jupyter Notebook主题皮肤并设置教程

    Jupyter Notebook的默认背景主题是白色 字体还不符合自己的眼光 看着实在费眼 也不够酷炫 我就不多赘述了 现在就来给我们的Jupyter notebook画一下妆 让它变得更加炫酷吧 1 安装 Jupyter 主题 通过命令行
  • PHP作业,cookie实现保存浏览历史,代码、运行截图、注释

    1 练习cookie的基本用法 理解cookie的工作原理 2 设计一个商品列表页面 数据从数据库读取 单击每个商品时 在新页面显示商品详情 通过cookie实现保存商品浏览历史 并显示在商品详情页的下方 浏览历史最多保存3条 提交代码截图
  • 两个有序序列的中位数(详解)

    1 实践题目 7 3 两个有序序列的中位数 2 问题描述 在一行中输出两个输入序列的并集序列的中位数 时间复杂度不能大于O logn 3 算法描述 不能粘贴程序 因为时间复杂度不能大于logn 所以把原序列排好序再来找中位数是不可能的了 快
  • float,double 的范围和有效数字怎么算出来的?

    首先说一下 范围是3 4E 38 3 4E 38 可提供7位有效数字 上述这两个量都是近似值 各个编译器不太一样的 下面我就将标准值是怎么定义的 和你说一下 这个比较复杂 建议你找一下IEEE754标准看一下 这个简单说一下吧 在IEEE7
  • 『坚如磐石的 PieCloudDB』:透明加密模块的设计与实现

    导读 2 月 17 日 由中国开源软件推进联盟 PostgreSQL 分会 中科院软件所 CSDN 联合举办的 中国 PostgreSQL 数据库生态大会 盛大召开 拓数派 OpenPie 作为冉冉升起的新一代云原生分布式数据库厂商 受邀参
  • 【C++】IO流

    文章目录 1 C语言的输入与输出 2 流是什么 3 C IO流 3 1 C 标准IO流 3 2 C 文件IO流 3 2 1 二进制读写 3 2 2 文本读写 4 stringstream 字符串流 的简单介绍 5 总结 1 C语言的输入与输
  • SQLite下载、安装与连接

    1 下载SQLite SQLite官网 https www sqlite org download html 根据自己电脑操作系统配置 选择32位或64位下载 一般情况下是64位 总共两个压缩包 或者直接去 https download c
  • 如何打造优秀Web3产品

    近日 我们采访了Mysten Labs的联合创始人兼首席执行官Evan Cheng 探讨了Web3技术对消费者的价值 Web3行业应该如何更好地自我诠释 以及它对产品开发的影响 您曾谈到Web3作为一种所有权实验 这种新技术可能会改变消费者
  • Oracle中的数据导出(4)

    目录 法一 使用SQL plus命令脚本 法二 使用PLSQL Developer工具 前几篇文章描述了如何将Oracle中的数据导出到库外 但是导出的数据结果都是文本文档 这样页面查看不和谐 编辑又略显麻烦 因此这篇文章将描述如何将Ora
  • 116_QT_RCC: Error in ‘file.qrc‘: Cannot find file

    有中文路径或者名字 导致找不到文件 全部改成英文就OK了
  • 数据耦合与控制耦合

    数据耦合 其中一个模块的输出作为另一个模块的输入 那么就存在数据耦合 如 Module A中 int FunA return 1 Module B中 int b FunA 上面两个modules就存在数据耦合 控制耦合 其中一个模块可以控制
  • C语言中对用户输入的数据使用冒泡排序法后输出

    代码 include stdio h include windows h int main 先定义一个数组a 变量i j和临时变量temp 用来存放临时数据 int a 5 i j temp printf Input Five Number
  • 点云双边滤波算法(附 matlab 代码)

    一 原理概述 在二维图像领域中 双边滤波算法是通过考虑中心像素点到邻域像素点的距离 一边 以及像素亮度差值所确定的权重 另一边 来修正当前采样中心点的位置 从而达到平滑滤波效果 同时也会有选择性的剔除部分与当前采样点 差异 太大的相邻采样点
  • ABA问题的解决

    什么是ABA问题 ABA问题是发生在CAS过程当中的下面以一个例子来表示 假如有两个线程A B 两个线程都从主内存中获取了某个对象的值为value1 当进行CAS的时候A首先把value1更换成了value2 因为线程B可能没有CPU资源调