我的编程空间,编程开发者的网络收藏夹
学习永远不晚

分析ABA问题的本质及其解决办法

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

分析ABA问题的本质及其解决办法

简介

CAS的原理其实很简单,为了保证在多线程环境下我们的更新是符合预期的,或者说一个线程在更新某个对象的时候,没有其他的线程对该对象进行修改。在线程更新某个对象(或值)之前,先保存更新前的值,然后在实际更新的时候传入之前保存的值,进行比较,如果一致的话就进行更新,否则失败。

注意,CAS在java中是用native方法来实现的,利用了系统本身提供的原子性操作。

那么CAS在使用中会有什么问题呢?一般来说CAS如果设计的不够完美的话,可能会产生ABA问题,而ABA问题又可以分为两类,我们先看来看一类问题。

第一类问题

我们考虑下面一种ABA的情况:

1.在多线程的环境中,线程a从共享的地址X中读取到了对象A。

2.在线程a准备对地址X进行更新之前,线程b将地址X中的值修改为了B。

3.接着线程b将地址X中的值又修改回了A。

4.最新线程a对地址X执行CAS,发现X中存储的还是对象A,对象匹配,CAS成功。

上面的例子中CAS成功了,但是实际上这个CAS并不是原子操作,如果我们想要依赖CAS来实现原子操作的话可能就会出现隐藏的bug。

第一类问题的关键就在2和3两步。这两步我们可以看到线程b直接替换了内存地址X中的内容。

在拥有自动GC环境的编程语言,比如说java中,2,3的情况是不可能出现的,因为在java中,只要两个对象的地址一致,就表示这两个对象是相等的。

2,3两步可能出现的情况就在像C++这种,不存在自动GC环境的编程语言中。因为可以自己控制对象的生命周期,如果我们从一个list中删除掉了一个对象,然后又重新分配了一个对象,并将其add back到list中去,那么根据 MRU memory allocation算法,这个新的对象很有可能和之前删除对象的内存地址是一样的。这样就会导致ABA的问题。

第二类问题

如果我们在拥有自动GC的编程语言中,那么是否仍然存在CAS问题呢?

考虑下面的情况,有一个链表里面的数据是A->B->C,我们希望执行一个CAS操作,将A替换成D,生成链表D->B->C。考虑下面的步骤:

1.线程a读取链表头部节点A。

2.线程b将链表中的B节点删掉,链表变成了A->C

3.线程a执行CAS操作,将A替换从D。

最后我们的到的链表是D->C,而不是D->B->C。

问题出在哪呢?CAS比较的节点A和最新的头部节点是不是同一个节点,它并没有关心节点A在步骤1和3之间是否内容发生变化。

我们举个例子:


public void useABAReference(){
    CustUser a= new CustUser();
    CustUser b= new CustUser();
    CustUser c= new CustUser();
    AtomicReference<CustUser> atomicReference= new AtomicReference<>(a);
    log.info("{}",atomicReference.compareAndSet(a,b));
    log.info("{}",atomicReference.compareAndSet(b,a));
    a.setName("change for new name");
    log.info("{}",atomicReference.compareAndSet(a,c));
}

上面的例子中,我们使用了AtomicReference的CAS方法来判断对象是否发生变化。在CAS b和a之后,我们将a的name进行了修改,我们看下最后的输出结果:

[main] INFO com.flydean.aba.ABAUsage - true

[main] INFO com.flydean.aba.ABAUsage - true

[main] INFO com.flydean.aba.ABAUsage - true

三个CAS的结果都是true。说明CAS确实比较的两者是否为统一对象,对其中内容的变化并不关心。

第二类问题可能会导致某些集合类的操作并不是原子性的,因为你并不能保证在CAS的过程中,有没有其他的节点发送变化。

第一类问题的解决

第一类问题在存在自动GC的编程语言中是不存在的,我们主要看下怎么在C++之类的语言中解决这个问题。

根据官方的说法,第一类问题大概有四种解法:

1.使用中间节点 - 使用一些不代表任何数据的中间节点来表示某些节点是标记被删除的。

2.使用自动GC。

3.使用hazard pointers - hazard pointers 保存了当前线程正在访问的节点的地址,在这些hazard pointers中的节点不能够被修改和删除。

4.使用read-copy update (RCU) - 在每次更新的之前,都做一份拷贝,每次更新的是拷贝出来的新结构。

第二类问题的解决

第二类问题其实算是整体集合对象的CAS问题了。一个简单的解决办法就是每次做CAS更新的时候再添加一个版本号。如果版本号不是预期的版本,就说明有其他的线程更新了集合中的某些节点,这次CAS是失败的。

我们举个AtomicStampedReference的例子:


public void useABAStampReference(){
    Object a= new Object();
    Object b= new Object();
    Object c= new Object();
    AtomicStampedReference<Object> atomicStampedReference= new AtomicStampedReference(a,0);
    log.info("{}",atomicStampedReference.compareAndSet(a,b,0,1));
    log.info("{}",atomicStampedReference.compareAndSet(b,a,1,2));
    log.info("{}",atomicStampedReference.compareAndSet(a,c,0,1));
}

AtomicStampedReference的compareAndSet方法,多出了两个参数,分别是expectedStamp和newStamp,两个参数都是int型的,需要我们手动传入。

总结

ABA问题其实是由两类问题组成的,需要我们分开来对待和解决。

以上就是分析ABA问题的本质及其解决办法的详细内容,更多关于ABA问题的本质及其解决办法的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

分析ABA问题的本质及其解决办法

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android 关于“NetworkOnMainThreadException”问题的原因分析及解决办法

网络收集的原因如下,以及解决办法:我补充总结一下:解决办法一: 在操作网络类(socket连接)的activity的protected void onCreate(Bundle savedInstanceState)函数后面加上下面的代码。
2022-06-06

vue-cli空格报错问题的分析及解决办法

作为前端开发者,我们经常会使用到 Vue.js 框架,而在 Vue.js 开始学习阶段,我们更多时候会借助 vue-cli 工具来快速构建和管理项目,然而 vue-cli 工具在使用过程中,我们也可能会遇到一些问题。本篇文章就来跟大家分享一下在使用 vue-cli 时遇到的空格报错问题及其解决方法。一、问题现象在使用 vue-cli 构建项目时,有时会遇到以下错误提示:```E
2023-05-14

java 中 poi解析Excel文件版本问题解决办法

poi解析Excel文件版本问题解决办法poi解析Excel文件时有两种格式: HSSFWorkbook格式用来解析Excel2003(xls)的文件 XSSFWorkbook格式用来解析Excel2007(xlsx)的文件 如果用HSSF
2023-05-31

MySQL 实例无法启动的问题分析及解决

前言前几天,有位朋友微信联系我,告知一个生产数据库,在机器宕机恢复后,实例启动失败,而且该实例没有做任何的高可用、容灾、备份等,对业务影响非常大,希望能够协助排查一下,我也在第一时间就加入到排查中。 场景分析(1)首先查看错误日志,报错很清
2022-05-26

Pandas出现KeyError的问题解决及分析

本文主要介绍了Pandas出现KeyError的问题解决及分析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2023-01-17

Oracle进程占用CPU100%的问题分析及解决方法

目录问题现象问题分析方法1方法2方法3解决方案问题现象linux环境,数据库CPU一直处于100%。业务系统运行很慢。Top命令结果如下:问题分析方法1根据上图中的oracle进程在操作系统对应的 PID号 : 如 6999,81
Oracle进程占用CPU100%的问题分析及解决方法
2024-08-22

MySQL无法修改主键的问题分析及解决方案

MySQL无法修改主键是由于主键信息存储在数据字典中,一经设置不可更改。解决方案包括:创建新表、添加唯一索引、修改主键列或使用触发器。预防措施是仔细考虑主键选择,使其唯一、稳定且有效。
MySQL无法修改主键的问题分析及解决方案
2024-04-02

"Method Not Allowed"405问题分析以及解决方法

项目中在提交表单时,提示“HTTP405”错误——“MethodNotAllowed”这里显示的是,方法不被允许,下面这篇文章主要给大家介绍了关于"Method Not Allowed"405问题分析以及解决方法的相关资料,需要的朋友可以参考下
2022-11-13

Win7系统安装遇到的问题及解决办法

问题1:屏幕出现Please wait...等待许久不见动静解决方法:这是Win7安装开始时安装程序加载时的提示语。如果卡在这个地方无法进行下去,请检查电脑硬件是否正常工作。但是如果电脑本身配置较低,可能要多等一下,稍安勿躁。问题2:屏幕
2023-06-03

Win8.1预览版常见问题以及解决办法大全(分享)

微软Win8.1预览版常见问题及解答大全: 一、 什么是Windows 8.1 Preview? Windows 8.1 Preview和Windows RT 8.1 Preview是Windows 8.1的预发行版本。它们是在Window
2022-06-04

pyqt5安装报错的常见问题及解决办法

随着Python的流行,PyQt5成为了很多人快速进行GUI开发的首选工具之一,但是,安装问题也是不可避免的。以下是几个PyQt5安装的常见问题及其解决方法。PyQt5安装时报错提示找不到sip模块的解决办法这个问题通常在使用pip安装
pyqt5安装报错的常见问题及解决办法
2024-01-19

java应用cpu占用过高问题分析及解决方法

使用jstack分析java程序cpu占用率过高的问题1,使用jps查找出java进程的pid,如37072,使用top -p 14292 -H观察该进程中所有线程的CPU占用。[root@cp01-game-dudai-0100.cp01
2023-05-31

总结分析Git pull 常见的错误及其解决方法

在使用 Git 进行项目协作时,我们经常会使用 git pull 命令来同步远程仓库中的代码到本地。尽管这个命令非常简单易用,但有时候可能会遇到各种各样的错误,甚至导致项目无法正常运行。本文将分析 Git pull 常见的错误及其解决方法。
2023-10-22

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录