我已经阅读过计算机科学中的ABA problem
(在并发环境中)
此外,我已经读过这个问题对于使用GC的语言来说并不实际。
现在我正在考虑java原子,我想知道这个问题是否被阻止,但我认为可能会出现这个问题。
让研究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调用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,然后执行CAS on V的时间。在这样的 一个案例,CAS操作会成功,但在某些情况下 结果可能不是你想要的。 (注意计数器和互斥锁 清单1和清单2中的示例不受此问题的影响,但是 并非所有算法都是。)这个问题被称为ABA问题,并且 通常通过将标签或版本号与...相关联来处理 要对每个值进行CASed,并以原子方式更新值和 标签。 AtomicStampedReference类为此提供支持 方法
请分享你的想法。
答案 0 :(得分:0)
对于整数递增例程,其他线程可能会在初始获取和比较并设置之间递增和递减一个值,但是如果其他线程的动作的组合作用是离开对象保留最初获取的相同值,然后写出一个比原始值大一个值的值将是正确的行为。例如,三个增量和一个减量的组合效果应是使对象保留的值比其原始值大两个值。如果第三个增量和减量发生在加载和第二次执行的比较设置之间,则写入的值将比该增量和减量之前观察到的值大一个,但写入后的净效果是增量和减量的发生都与在发生增量和减量之前写的相同。如果仅在获取和比较与设置之间发生增量,则将导致比较与设置失败并重新执行循环。
在不扫描垃圾收集器的语言中,ABA问题主要是在使用指针时出现的,因为在CompareAndSet循环执行指针的旧值的首次获取与CompareAndSet的操作之间,可能会释放指针并替换为指向恰好具有相同地址的另一个对象的指针。 Java的扫描GC将使此类问题成为不可能,但是,因为在CompareAndSet循环中对对象的引用将防止其被垃圾回收。在Java中,唯一可以进行垃圾回收的对象是将永远不存在引用的对象(在强引用可能的情况下,JVM可以准备一个对象进行垃圾回收)例如通过检查弱引用或finalize()
的结果而存在,但是直到穷尽了所有引用的存在才可能真正地收集对象)。