CAS产生的ABA问题

您所在的位置:网站首页 cas产生的问题 CAS产生的ABA问题

CAS产生的ABA问题

2024-07-09 03:38| 来源: 网络整理| 查看: 265

ABA问题是什么

 

狸猫换太子

假设现在有两个线程,分别是T1 和 T2,然后T1执行某个操作的时间为10秒,T2执行某个时间的操作是2秒,最开始AB两个线程,分别从主内存中获取A值,但是因为B的执行速度更快,他先把A的值改成B,然后在修改成A,然后执行完毕,T1线程在10秒后,执行完毕,判断内存中的值为A,并且和自己预期的值一样,它就认为没有人更改了主内存中的值,就快乐的修改成B,但是实际上 可能中间经历了 ABCDEFA 这个变换,也就是中间的值经历了狸猫换太子。

所以ABA问题就是,在进行获取主内存值的时候,该内存值在我们写入主内存的时候,已经被修改了N次,但是最终又改成原来的值了

CAS导致ABA问题

CAS算法实现了一个重要的前提,需要取出内存中某时刻的数据,并在当下时刻比较并替换,那么这个时间差会导致数据的变化。

比如说一个线程one从内存位置V中取出A,这时候另外一个线程two也从内存中取出A,并且线程two进行了一些操作将值变成了B,然后线程two又将V位置的数据变成A,这时候线程one进行CAS操作发现内存中仍然是A,然后线程one操作成功

尽管线程one的CAS操作成功,但是不代表这个过程就是没有问题的

ABA问题

CAS只管开头和结尾,也就是头和尾是一样,那就修改成功,中间的这个过程,可能会被人修改过

原子引用

原子引用其实和原子包装类是差不多的概念,就是将一个java类,用原子引用类进行包装起来,那么这个类就具备了原子性

/** * @author HX * @title: AtomicReferenceDeo * @projectName spring_cloud1x * @date 2022/5/9 9:47 * 原子引用 */ @Data @AllArgsConstructor @NoArgsConstructor class User{ private String name; private Integer age; } public class AtomicReferenceDemo { public static void main(String[] args) { User lisi = new User("lisi", 20); User zs = new User("张三", 20); //原子引用 主内存共享变量lisi AtomicReference reference=new AtomicReference(); reference.set(lisi); // 比较并交换,若预期值===真实值 修改为zs System.out.println(reference.compareAndSet(lisi, zs)+"\t"+reference.get()); System.out.println(reference.compareAndSet(lisi, zs)+"\t"+reference.get()); } }

 基于原子引用的ABA问题

我们首先创建了两个线程,然后T1线程,执行一次ABA的操作,T2线程在一秒后修改主内存的值

/** * @author HX * @title: ABADemo * @projectName spring_cloud1x * @date 2022/5/9 10:02 * 产生ABA问题演示 */ public class ABADemo { private static AtomicReference atomicReference = new AtomicReference(100); public static void main(String[] args) { //产生ABA问题 new Thread(() -> { // 把100 改成 127 然后在改成100,也就是ABA System.out.println(atomicReference.compareAndSet(100, 127) + "\t" + atomicReference.get()); System.out.println(atomicReference.compareAndSet(127, 100) + "\t" + atomicReference.get()); }, "线程A").start(); new Thread(() -> { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("------------------------------"); System.out.println(atomicReference.compareAndSet(100, 2022)+"\t"+atomicReference.get()); }, "线程B").start(); } }

它能够成功的修改,这就是ABA问题

解决ABA问题

新增一种机制,也就是修改版本号,类似于时间戳的概念

AtomicStampedReference


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3