1.volatile是java虚拟机提供的轻量级的同步机制,三个特点①保证可见性(JMM模型)②不保证原子性(存在往主内存写数据时覆盖)③禁止指令重排。
2.如何解决原则性:①加sync锁②使用JUC包下AtomicInteger类(CAS原理)
3.CAS(compareAndSwap)底层原理unsafe类:比较当前工作内存中的值和主内存中的值,如果相同则指定规定操作,否则继续比较直到主内存和工作内存中的值一致性。
4.CAS有3个操作数,内存值V,旧的预期值A,要修改的更新值B,当且仅当预期值A和内存值V相同时,将内存值修改为B否则什么也不做。CAS缺点①循环时间长开销大,②只能保证一个共享变量的原子操作③引出ABA问题。
5.CAS会导致ABA问题:
CAS算法实现一个重要前提时需要去除内存中某时刻的数据并在当下时刻比较并替换,那么在这个时间差里会导致数据变化。
比如说一个线程one从内存位置V取出A,这时候另一个线程two也从内存中取出A,并且线程two进行了一些操作将值变成了B,然后线程two又将V位置的数据变成A,这时候线程one进行CAS操作发现内存中仍然是A,然后线程one操作成功,尽管线程One的CAS操作成功,但是并不代表这个过程就是没有问题的。
/**
* 描述: CAS导致的ABA问题的解决 AtomicStampReference类
*
* @author [email protected]
* @create 2020/2/21 11:55
* @since 2.16.3
*/
public class ABADemo {
static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
// 解决ABA问题的类AtomicStampedReference类(初始值,初始版本号)
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();
System.out.println("----------------以下是ABA问题的解决-------------");
new Thread(()-> {
// 版本号
int stamp = atomicStampedReference.getStamp();
System.out.println(Thread.currentThread().getName()+"\t第一次版本号"+stamp);
// 暂停1秒钟t3线程
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第2次版本号"+atomicStampedReference.getStamp());
atomicStampedReference.compareAndSet(101, 100, atomicStampedReference.getStamp(), atomicStampedReference.getStamp()+1);
System.out.println(Thread.currentThread().getName()+"\t第3次版本号"+atomicStampedReference.getStamp());
}, "t3").start();
new Thread(()-> {
// 版本号
int stamp = atomicStampedReference.getStamp();
System.out.println(Thread.currentThread().getName()+"\t第一次版本号"+stamp);
// 暂停3秒钟t4线程,保证上面的t3线程完成了一次ABA操作
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+"\t当前版本号"+atomicStampedReference.getStamp());
System.out.println(Thread.currentThread().getName()+"\t当前实际最新值"+atomicStampedReference.getReference());
}, "t4").start();
}
}