Java多线程-2-CAS

二、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

猜你喜欢

转载自blog.csdn.net/adsl624153/article/details/103865205