ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CAS引起的ABA问题

2021-06-10 20:34:59  阅读:164  来源: 互联网

标签:ABA CAS 引起 System getStamp 线程 println 100 atomicStampedReference


ABA问题的产生

​ CAS算法实现的核心是需要取出内存中某个时刻的数据并在当下时刻比较并替换。那么在这个时间差类会导致数据的变化。比如一个线程one从内存位置v取值a,这时候另一个线程two也从内存中取出a,并且线程two进行了一些操作将值变成了b。然后two又将v位置的数据变成了a。这时候线程one进行cas操作发现内存中任然是a。然后线程one操作成功。尽管线程one的cas操作成功了,但是不代表这个过程就是没有问题的。

 

ABA问题示例一:

public class AtomicStampedReferenceDemo {

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

    public static void main(String[] args) {

        new Thread(()->{
       //将100替换成101了,然后又把101变成100,因为线程B暂停了1妙钟。没有发现线程A值已经变换过,于是变换成功。
            atomicReference.compareAndSet(100,101);
            atomicReference.compareAndSet(101,100);
        },"线程A").start();

        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            atomicReference.compareAndSet(100,2019);
            System.out.println(atomicReference.get());
        },"线程B").start();
    }
    
}

ABA问题示例二:

如上图所示,现有一个用单向链表实现的堆栈,栈顶为A,这时线程T1已经知道 A next为B,然后希望用CAS将栈顶替换为B
head. compareAndSet(A, B)
在T执行上面这条指令之前,线程T介入,将A、B出栈,再 pushD、C、A,此时堆栈结构如下图,而对象B此时处于游离状态

此时轮到线程T1执行CAS操作,检测发现栈顶仍为A,所以CAS成功,栈顶变为B,但实际上B,next为nul,所以此时的情况变为

其中堆栈中只有B一个元素,C和D组成的链表不再存在于堆栈中,平白无故就把C、D丢掉了。

 

ABA问题的解决

aba问题解决代码示例

public class AtomicStampedReferenceDemo {

    private static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1);

    public static void main(String[] args) {

        new Thread(() -> {
            System.out.println("线程A第1次版本号:" + atomicStampedReference.getStamp());
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            atomicStampedReference.compareAndSet(100, 101, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
            System.out.println("线程A第2次版本号:" + atomicStampedReference.getStamp());
            atomicStampedReference.compareAndSet(101, 100, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
            System.out.println("线程A第3次版本号:" + atomicStampedReference.getStamp());
        }, "线程A").start();

        new Thread(() -> {
            int stamp = atomicStampedReference.getStamp();
            System.out.println("线程B第1次版本号:" + atomicStampedReference.getStamp());
          //睡眠3秒,是为了让线程A完成ABA操作
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程B第2次版本号:" + atomicStampedReference.getStamp());
            boolean success = atomicStampedReference.compareAndSet(100, 2019, stamp, stamp + 1);
            System.out.println(success);
            System.out.println(atomicStampedReference.getReference() + "---" + atomicStampedReference.getStamp());
        }, "线程B").start();
    }
}

标签:ABA,CAS,引起,System,getStamp,线程,println,100,atomicStampedReference
来源: https://www.cnblogs.com/gaoweiBlog/p/14872517.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有