java原子类防止ABA问题?

问题描述 投票:0回答:1

我读过关于 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增量或增量,值溢出,但旧值与新值相等。

让我们研究一下场景(Thred 1和Thread 2做增量,但Thread 3 - 减量)。

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

附注

来自 http:/www.ibm.comdeveloperworkslibraryj-jtp11234

ABA问题 由于CAS基本上是在改变V之前询问 "V的值是否仍然是A",所以基于CAS的算法有可能在第一次读取V和对V执行CAS的时间之间,被从A到B再回到A的值所迷惑。在这种情况下,CAS操作会成功,但在某些情况下,结果可能不是想要的。(请注意,清单1和清单2中的计数器和mutex例子对这个问题是免疫的,但并不是所有算法都能免疫)。这个问题被称为 ABA 问题,通常是通过为每个要 CAS 的值关联一个标签或版本号,并原子地更新值和标签来处理的。AtomicStampedReference类提供了对这种方法的支持。

请大家分享一下自己的想法。

java concurrency atomic
1个回答
0
投票

在整数增量例程的情况下,其他线程有可能在初始获取和比较和设置之间增减一个值,但如果其他线程的行为的综合效果是让对象持有与初始获取的值相同的值,那么写出一个比原始值大一的值将是正确的行为。 例如,三次增量和一次减量的综合效果应该是让对象持有一个比其原始值大两个的值。 如果第三个增量和减量发生在第二个增量和减量执行的加载和比较与设置之间,则写入的值将比增量和减量之前观察到的值大一个,但在增量和减量发生后写入该值的净效果与在增量和减量发生前写入该值的净效果相同。 如果只有增量发生在取值和比较与设置之间,那就会导致比较与设置失败,循环被重新执行。

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

© www.soinside.com 2019 - 2024. All rights reserved.