java原子类防止ABA问题?

Posted

技术标签:

【中文标题】java原子类防止ABA问题?【英文标题】:java atomic classes prevent ABA issue? 【发布时间】:2017-02-07 07:58:21 【问题描述】:

我在计算机科学(在并发环境中)阅读了有关 ABA problem 的信息

我还读到这个问题对于带有 GC 的语言并不实际。

现在我正在考虑 java atomics,我想知道这个问题是否被阻止,但我认为这个问题可能会发生。

让我们研究一下AtomicInteger 和 java 6 的实现

每个方法大致如下:

private volatile int value;

public int incrementAndGet() 
    while(true)
        int old = value; //1
        int newValue = value+1;
        if(compareAndSet(old, newValue)) //2
            return newValue;
        
    

看起来在//1//2 之间,其他线程可以执行递增和递减,并且将添加此检查,但根据我的理解,这是错误的,这是 ABA 问题的表现。 或者例如在 //1//2 之间发生 Integer.MAX_VALUE 递增或递增,值溢出但旧值等于新值

让研究场景(线程 1 和线程 2 递增,线程 3 - 递减):

线程 1 调用 get 并获取值 1。 线程 1 计算下一个为 2。 线程 2 调用 get 并获取值 1。 线程 2 计算 next 为 2。 线程 2 调用 compareAndSet 并获得成功 线程 3(递减线程)调用 get 并获取值 2。 线程 3 调用 compareAndSet 并获得成功 线程 1 调用 compareAndSet 并获得成功

附言

来自:http://www.ibm.com/developerworks/library/j-jtp11234/

ABA问题因为CAS基本上是问“V的值还是A” 在改变 V 之前,基于 CAS 的算法可能是 被从 A 变为 B 并返回到 A 之间的值混淆 首次读取 V 的时间和对 V 执行 CAS 的时间。在这样的 在一个案例中,CAS 操作会成功,但在某些情况下 结果可能不是我们想要的。 (注意计数器和互斥锁 清单 1 和清单 2 中的示例不受此问题的影响,但是 并非所有算法都是。)这个问题被称为 ABA 问题,并且 通常通过将标签或版本号与 每个值都被 CAS 化,并以原子方式更新值和 标签。 AtomicStampedReference 类为此提供支持 接近。

请分享你的想法。

【问题讨论】:

您需要了解compareAndSet 的作用。只有当当前值等于old时才会更新,然后将其设置为new;这是原子完成的。如果值同时发生变化,则返回false,并循环再次尝试。 @Mark Rotteveel,我理解这一点,但是正如我在 //1 和 //2 之间写的那样,其他线程可以执行递增和递减,因此值看起来没有改变,但它错了 你错了,因为compareAndSet 的实现正好可以防止这个问题。 @Mark Rotteveel,来自您的链接:保证该值与指定值相同,并且现在为新值。 另外,如果交错操作改变了值,所以它仍然和旧的一样,它真的改变了吗?从操作的最终结果来看是无关紧要的。 【参考方案1】:

在整数增量例程的情况下,其他线程可能会在初始获取和比较和设置之间增加和减少一个值,但是如果其他线程的操作的组合效果是离开对象保持最初获取的相同值,然后写出比原始值大一的值将是正确的行为。例如,三个增量和一个减量的组合效果应该是让一个对象保持比其原始值大两倍的值。如果第三次递增和递减发生在加载和第二次执行的比较和设置之间,则写入的值将比在递增和递减之前观察到的值大一,但是在之后写入该值的净效果增加和减少都发生了,这与在任何一个发生之前写入它是一样的。如果仅在 fetch 和 compare-and-set 之间发生增量,那将导致 compare-and-set 失败并重新执行循环。

在没有扫描垃圾收集器的语言中,ABA 问题主要出现在使用指针时,因为在 CompareAndSet 循环执行第一次获取指针的旧值和执行 CompareAndSet 操作之间,指针可能会被释放并替换为指向恰好具有相同地址的不同对象的指针。然而,Java 的扫描 GC 将使此类问题变得不可能,因为在 CompareAndSet 循环中对对象的引用会阻止它被垃圾收集。 Java 中唯一可以被垃圾回收的对象是那些永远不会存在引用的对象(JVM 可能准备一个对象用于垃圾回收,以防强引用可能例如通过检查弱引用或finalize() 的结果而存在,但在所有引用存在的可能性都用尽之前无法实际收集对象)。

【讨论】:

以上是关于java原子类防止ABA问题?的主要内容,如果未能解决你的问题,请参考以下文章

原子类的ABA问题

Java底层类和源码分析系列-AtomicStampedReference解决ABA问题

JDK源码并发原子类AtomicStampedReference

CAS你知道吗?原子类AtomicInteger的ABA问题谈谈?

多线程 CAS 机制解析及应用( 原子类 . 自旋锁 )解决 ABA 问题

CAS,在硬件层面为并发安全保驾护航