目录

使用AtomicStampedReference 解决ABA问题

示例代码

使用AtomicMarkableReference解决问题

示例代码


什么是ABA

有一个链表里面的数据是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,这个就是ABA问题。那么如何解决这个问题呢?下面就介绍两种解决ABA的方法。

使用AtomicStampedReference 解决ABA问题

JDK提供了AtomicStampedReference来解决ABA问题,它在CAS的基础上增加了一个邮戳stamp来标记数据是否发生了变化。,如果邮戳不符合预期则修改失败。

示例代码

public class AtomicStampedReferenceTest {public void test() {CountDownLatch latch = new CountDownLatch(2);AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(1, 0);ExecutorService executorService = Executors.newCachedThreadPool();executorService.submit(() -> {try {boolean success;//获取当前邮戳int stamp = atomicStampedReference.getStamp();System.out.println("[A] before sleep  value is " + atomicStampedReference.getReference() + " stamp is " + stamp);TimeUnit.SECONDS.sleep(5);//将1,改为 10success = atomicStampedReference.compareAndSet(1, 10, stamp, stamp + 1);System.out.println("[A-1] after sleep, success:  " + success + "  value is " + atomicStampedReference.getReference() + " stamp is " + stamp);stamp++;//再次将10 改为1 atomicStampedReference.compareAndSet(10, 1, stamp, stamp + 1);System.out.println("[A-2] after sleep, success:  " + success + "  value is " + atomicStampedReference.getReference() + " stamp is " + stamp);latch.countDown();} catch (Exception e) {e.printStackTrace();}});executorService.submit(() -> {try {boolean success;int stamp = atomicStampedReference.getStamp();System.out.println("[B] before sleep  value is " + atomicStampedReference.getReference() + " stamp is " + stamp);TimeUnit.SECONDS.sleep(10);success = atomicStampedReference.compareAndSet(1, 20, stamp, stamp + 1);System.out.println("[B-1] after sleep, success:  " + success + "  value is " + atomicStampedReference.getReference() + " stamp is " + stamp);latch.countDown();} catch (Exception e) {e.printStackTrace();}});}public static void main(String[] args) {new AtomicStampedReferenceTest().test();}
}

测试结果如下:

[A] before sleep  value is 1 stamp is 0
[B] before sleep  value is 1 stamp is 0
[A-1] after sleep, success:  true  value is 10 stamp is 0
[A-2] after sleep, success:  true  value is 1 stamp is 1
[B-1] after sleep, success:  false  value is 1 stamp is 0

使用AtomicMarkableReference解决问题

上文我们使用AtomicStampedReference来解决ABA问题,很多时候我们并不关心它的邮戳,也就是我们不需要知道修改过几次,我们关系的仅仅是有没有修改过。此时我们就可以使用AtomicMarkableReference来解决这个问题。

示例代码

public class AtomicMarkableReferenceTest {public void test() {CountDownLatch latch = new CountDownLatch(2);AtomicMarkableReference<Integer> atomicMarkableReference = new AtomicMarkableReference<>(1, false);ExecutorService executorService = Executors.newCachedThreadPool();executorService.submit(() -> {try {boolean success;//获取当前邮戳boolean[] arr = new boolean[]{false};Integer currentValue = atomicMarkableReference.get(arr);boolean mark = arr[0];System.out.println("[A] before sleep  value is " + currentValue + " mark is " + mark);TimeUnit.SECONDS.sleep(5);//将1,改为 10success = atomicMarkableReference.compareAndSet(1, 1, mark, !mark);System.out.println("[A-1] after sleep, success:  " + success + "  value is " + atomicMarkableReference.getReference() + " mark is " + getMark(atomicMarkableReference));latch.countDown();} catch (Exception e) {e.printStackTrace();}});executorService.submit(() -> {try {boolean success;//获取当前邮戳boolean[] arr = new boolean[]{false};Integer currentValue = atomicMarkableReference.get(arr);boolean mark = arr[0];System.out.println("[B] before sleep  value is " + currentValue + " mark is " + mark);TimeUnit.SECONDS.sleep(10);success = atomicMarkableReference.compareAndSet(1, 20, mark, !mark);System.out.println("[B-1] after sleep, success:  " + success + "  value is " + atomicMarkableReference.getReference() + " mark is " + getMark(atomicMarkableReference));latch.countDown();} catch (Exception e) {e.printStackTrace();}});}private boolean getMark(AtomicMarkableReference<Integer> atomicMarkableReference) {boolean[] arr = new boolean[]{false};atomicMarkableReference.get(arr);return arr[0];}public static void main(String[] args) {new AtomicMarkableReferenceTest().test();}
}

测试结果

[A] before sleep  value is 1 mark is false
[B] before sleep  value is 1 mark is false
[A-1] after sleep, success:  true  value is 1 mark is true
[B-1] after sleep, success:  false  value is 1 mark is true

【面试】五分钟掌握ABA问题以及解决办法相关推荐

  1. JUC04-- CAS自旋 、CAS自旋锁、ABA问题及解决办法、18大原子类

    文章目录 JUC04 课程任务概览 CAS CAS原理简介 CAS发展: CAS是什么? CAS原理: CAS优点: **CAS底层实现-引出Unsafe类** ==CAS自旋实现个人总结== Ato ...

  2. win10锁屏后默认1分钟进入睡眠状态的解决办法

    问题描述 先说一下睡眠和关闭显示器的区别:睡眠时系统中的一部分程序会停止工作,当你唤醒时会有卡顿感.而关闭显示器的话,其实程序还是在工作的,仅仅是不显示了.从仅关闭显示器的状态唤醒时,体验会比较流畅. ...

  3. 手机连接小爱音箱15分钟后自动断开的解决办法

    问题描述: 蓝牙设备连接小爱触屏音箱15分钟后会自动断开连接. 解决办法: 小爱没有被蓝牙设备连接时,15分钟后会关闭蓝牙,不过用手机还是可以连接上的.下次用蓝牙连接小爱同学前,先把小爱同学的蓝牙开关 ...

  4. 联想Thinkpad E480笔记本电脑2分钟后自动黑屏解决办法

    背景:2018年买的一台办公本联想Tinkpad E480,除非播放视频或者音频,否则2分钟左右就自动黑屏,查阅了好几次网上的解决办法,联系了联想官方客服,均未得到解决,最近终于找到了一个解决的办法, ...

  5. 第五人格获取服务器信息失败,第五人格正在获取版本信息解决办法 [图]

    第五人格正在获取版本信息怎么回事?相信最近很家在进入第五人格游戏的时候一直会卡在一个显示"正在获取版本信息"的界面,而且在获取一段时间后再显示获取更新失败,请重新尝试,那么这个是什 ...

  6. 计算机10分钟不用就自动重启,Win10开机后提示你的电脑将在一分钟后自动重启的解决办法...

    我们在使用Win10系统时电脑一开机就出现,你的电脑将在一分钟后自动重启,有时还会蓝屏,错误代码0xc0000001,遇到这种问题我们要怎么解决呢?下面就跟着小编一起看看解决办法吧. 解决方法如下: ...

  7. ABA问题及解决办法

    一个线程把数据A变为了B,然后又重新变成了A.此时另外一个线程读取的时候,发现A没有变化,就误以为是原来的那个A.这就是有名的ABA问题.ABA问题会带来什么后果呢?我们举个例子. 一个小偷,把别人家 ...

  8. cas引出的ABA问题?如何解决?- 理解原子引用、时间戳(版本号)原子引用

    ABA问题: 假如有两个线程1,2: cas下:1.线程取值完等待,2线程取值并把A改成B,有把B改成A,这是1线程执行会任务A还是原来的A没有发生改变,如果不在乎中间结果,只看收尾,那么没必要解决A ...

  9. ABA问题的解决方法

    CAS操作可能带来ABA问题,因为CAS操作需要在操作值的时候,检查值有没有发生变化,如果没有发发生变化则更新.如果一个值原理是A,变成了B,又变成了A,那么使用CAS进行检查时会认为它的值没有变化, ...

最新文章

  1. bat 两个文本字符替换_数据人必会的Excel|掌握这些文本函数,让你的工作如鱼得水...
  2. 计算机体系结构--第一章1----体系结构的分类
  3. 自然语言处理 —— 困惑度
  4. 物联网系统开发如何选择时序数据库
  5. 和为s的两个数字 - 双指针
  6. docker pull命令入门
  7. windows快捷键完整版分享
  8. besiege机器人_围攻besiege机器人 机器人制作思路
  9. Android基于百度地图的拖拽定位(地图可以拖动,定位图标不动)
  10. 认识计算机系统授课计划,计算机网络技术基础授课计划.doc
  11. 景深决定照相机什么特性_照相机光圈与景深的关系
  12. mysql日期相减返回秒_mysql两个日期相减得到秒、分、天
  13. 电脑如何批量下载哔哔视屏_我是电脑哔哔哔哔哔
  14. 用C语言将整数翻译为英文,C语言实现翻译功能
  15. Unity3D - 【Terrain】树木与草地
  16. NUS CS5477 assignment1
  17. java 使用GDAL读取
  18. 一个比StegSolve更方便的工具—zsteg
  19. Android Service服务保活
  20. Trends综述 | 李猛组-古菌在滨海生态系统的碳循环过程发挥的重要作用

热门文章

  1. Microsoft Access 安装教程
  2. iar使用秉火DAP仿真时出现错误 Download error at 0x08000000: downloading into non-writable memory.
  3. Elasticsearch学习(2) 基本概念
  4. matlab线性回归结果,利用Matlab进行线性回归分析
  5. 七麦数据:2018年App Store大数据半年盘点(附下载)
  6. 校招软件测试面经篇一(互联网企业)
  7. JS控制GIF图片的停止与显示(掷骰子实现)
  8. javascript特效大集合
  9. 智能小车项目之L9110前后左右控制小车
  10. 选择大于努力,阿里工程师有话说~