CAS 操作 与 ABA问题

compareAndSet 函数交CAS操作

AtomicInteger atomicInteger = new AtomicInteger();
atomicInteger.compareAndSet(0,2);
<p>public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}</p>
<p>valueOffset 是一个地址偏移量,this是自身对象,通过 this + valueOffset取出来的值,对比expect
相等则 更新值为update
我们来看看atomicInteger.getAndIncrement();方法,这方法是++操作的原子操作
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}</p>
<p>public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));</p>
<pre><code>    return var5;
}

通过不断去取valueOffeset 保证自己取到的值,与开始修改的值是一样的为止,去做+1操作, 防止其他线程修改了,来保证自己的修改操作是原子性的

但是有个其他情况,ABA 其他线程修改完,又修改回来了,我拿到的值是别人改过的,虽然这个值是对的、但是还是很奇怪的bug

看看危害

ABA问题带来的危害: 小明在提款机,提取了50元,因为提款机问题,有两个线程,同时把余额从100变为50 线程1(提款机):获取当前值100,期望更新为50, 线程2(提款机):获取当前值100,期望更新为50, 线程1成功执行,线程2某种原因block了,这时,某人给小明汇款50 线程3(默认):获取当前值50,期望更新为100, 这时候线程3成功执行,余额变为100, 线程2从Block中恢复,获取到的也是100,compare之后,继续更新余额为50!!! 此时可以看到,实际余额应该为100(100-50+50),但是实际上变为了50(100-50+50-50)这就是ABA问题带来的成功提交。

链接:https://juejin.cn/post/6844903796129136647

解决问题的方法,在修改操作时候加版本号

AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(1,1);
System.out.println(atomicStampedReference.compareAndSet(1, 2, 1, 2));
System.out.println(atomicStampedReference.getStamp());
System.out.println(atomicStampedReference.getReference());</p>
<p>public boolean compareAndSet(V   expectedReference,
V   newReference,
int expectedStamp,
int newStamp) {
Pair<V> current = pair;
return
expectedReference == current.reference &&
expectedStamp == current.stamp &&
((newReference == current.reference &&
newStamp == current.stamp) ||
casPair(current, Pair.of(newReference, newStamp)));
}</p>
<p>private boolean casPair(Pair<V> cmp, Pair<V> val) {
return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
}</p>
<p>不会循环等待,被修改过了直接返回false不给,更新