ABA问题:
假如有两个线程1,2;
cas下:1.线程取值完等待,2线程取值并把A改成B,有把B改成A,这是1线程执行会任务A还是原来的A没有发生改变,如果不在乎中间结果,只看收尾,那么没必要解决ABA问题
如何解决?
使用AtomicStampedRefererce,加版本号
代码演示如下:
package Volatile;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;
/**
* ABA问题的解决办法 AtomicStampedReference 时间戳原子引用·
*/
public class ABA {
static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100,1);
public static void main(String []args){
System.out.println("==========以下是ABA问题的产生=======");
new Thread(()->{
atomicReference.compareAndSet(100,101);
atomicReference.compareAndSet(101,100);
},"t1").start();
new Thread(()->{
//暂停1秒t2线程,保证t1完成一次ABA
try {TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace();}
System.out.println(atomicReference.compareAndSet(100,2019)+"\t"+atomicReference.get());
},"t2").start();
try {TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace();}
System.out.println("=========以下是ABA问题的解决==========");
new Thread(()->{
int stamp = atomicStampedReference.getStamp();
System.out.println(Thread.currentThread().getName()+"\t第一次版本号:"+atomicStampedReference.getStamp());
//暂停1秒t3线程,让t4也获取到一样的stamp
try {TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace();}
atomicStampedReference.compareAndSet(100,101,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
System.out.println(Thread.currentThread().getName()+"\t第二次版本号:"+atomicStampedReference.getStamp());
atomicStampedReference.compareAndSet(101,100,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
System.out.println(Thread.currentThread().getName()+"\t第三次版本号:"+atomicStampedReference.getStamp());
},"t3").start();
new Thread(()->{
int stamp = atomicStampedReference.getStamp();
System.out.println(Thread.currentThread().getName()+"\t第一次版本号:"+atomicStampedReference.getStamp());
//暂停1秒t3线程
try {TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace();}
boolean result = atomicStampedReference.compareAndSet(100, 2019, stamp, stamp + 1);
System.out.println(Thread.currentThread().getName()+"\t修改功否:"+result);
System.out.println(Thread.currentThread().getName()+"\t当前实际最新值:"+atomicStampedReference.getReference());
},"t4").start();
}
}