二、CAS
1、概念
CAS(compareAndSwap),比较并交换
CAS操作需要输入两个值,一个旧值(操作前的值),一个新值(要操作的值)。在操作期间首先比较旧值有没有发生改变,如果没有变化,则交换成新值,否则不交换
主要用于java.util.concurrent
包下的多个类(lock、atomic)的底层实现,核心类是sun.misc.Unsafe
,类里的方法大都是native方法,因为它调用的是操作系统底层的汇编指令
2、Java实现原子操作
除了使用锁以外,还可以使用自旋 + CAS
自旋是为了减少线程上下文切换的开销
3、CAS实现原子操作的三大问题
【1】ABA问题
问题描述:因为CAS操作的时候,需要进行比较。如果旧值被修改多次,而恰好最后一次更新的值是本次比较的旧值,这样就会把本不应该更新的情况,给更新了
解决办法:使用版本号来追加判断。不仅比较值是否相同,还要比较版本号是否符合逻辑
【2】自旋时间长导致开销大
问题描述:如果CAS操作一直不成功,就会导致自旋时间过长,这样就给CPU带来非常大的执行开销(CPU使用率提高)
解决办法:如果JVM能支持处理器提供的pause指令,那么效率会有一定的提升。睡一会儿
【3】只能保证一个共享变量的原子操作
问题描述:CAS操作同一时间,只能比较一个值
解决办法:加锁。或者把多个共享变量合并成一个共享变量来操作,比如使用java.util.concurrent.atomic.AtomicReference
4、java.util.concurrent.atomic相关类
【1】AtomicInteger
AtomicInteger atomicInteger = new AtomicInteger(10);
boolean compareAndSet = atomicInteger.compareAndSet(10, 20);
System.out.println(compareAndSet); // true
System.out.println(atomicInteger.get()); // 20
System.out.println(atomicInteger.incrementAndGet()); // 21
System.out.println(atomicInteger.decrementAndGet()); // 20
【2】AtomicReference
Object obj1 = new Object();
System.out.println("obj1:" + obj1);
AtomicReference<Object> atomicReference = new AtomicReference<Object>(obj1);
Object obj2 = new Object();
System.out.println("obj2:" + obj2);
Object getAndSet = atomicReference.getAndSet(obj2);
System.out.println("旧值:" + getAndSet); // obj1
System.out.println("新值:" + atomicReference.get()); // obj2
【3】AtomicStampedReference
Object obj1 = new Object();
int stamp = 1;
AtomicStampedReference<Object> atomicStampedReference = new AtomicStampedReference<Object>(obj1, stamp);
Object obj2 = new Object();
System.out.println("obj2:" + obj2);
stamp = 2;
boolean compareAndSet = atomicStampedReference.compareAndSet(obj1, obj2, 1, stamp);
System.out.println(compareAndSet); // true
System.out.println(atomicStampedReference.getReference()); // obj2
System.out.println(atomicStampedReference.getStamp()); // 2