CAS compare and swap 比较并交换
public class CASDemo { public static void main(String[] args){ AtomicInteger atomicInteger = new AtomicInteger(5); System.out.println(atomicInteger.compareAndSet(5,2019)+"\t current data: "+atomicInteger.get()); System.out.println(atomicInteger.compareAndSet(5,1024)+"\t current data: "+atomicInteger.get()); } }
CAS的底层源码:
- this;当前对象
- valueOffset: 内存地址
- expect:期待值
- update:更新值
Unsafe类:
是CAS的核心类,由于Java方法无法直接访问底层操作系统,需要通过本地方法来访问。Unsafe类相当于一个后门,基于该类可以直接操作特定内存的数据。Unsafe类在sun.misc包中,其内部方法操作可以像C的指针一样直接操作内存
Unsafe类中的所有方法都是native修饰的(不对啊,很多方法明明没加native)
CAS并发原语体现在Java中就是Unsafe类中的各个方法。调用Unsafe类中的CAS方法,JVM会帮我们是先出CAS汇编指令。
这是一种完全依赖于硬件的功能,通过它实现了原子操作。
原语属于操作系统用语范畴,是由若干条指令组成的,用于完成某个功能的一个剁成,并且原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成的数据不一致问题。
CAS的实现核心:
- 自旋
- unsafe类与内存值作比较。
Unsafe类的getAndAddInt()源码
- 参数列表:
- - var1 AtomicInteger本身
- - var2 变量var1的内存地址
- - var3
- - var4 值修改的量,比如加1的这个1
- - var5 通过内存地址找出的当前时间保存在这个位置上的值
- 方法执行过程:
- 取出地址上的值var5,并与var1比较(我感觉应该是var5和var2地址上的值比较,如果是var5和var1比较不久死循环了吗)
- 如果一致,说明没有被修改(这里先不考虑ABA问题)。就可以将var4+var5的值写到这个地址上,compareAndSwapInt()方法返回true,结束do-while循环
- 如果不一致,就继续执行do-while循环,这个循环称为自旋
- 问题:如果不一致,在这个方法里不是死循环了?
- 回答:不会,因为do-while的方法体里会读取一次var5,不可能一直死循环
为什么用CAS而不用synchronized
synchronized加锁,一致性得到保障,但是并发性下降,CAS既保证了一致性又保证了并发性
CAS的缺点
- 比较失败会一直尝试,如果长时间不成功,可能会给CPU带来很大的开销
- 只能保证一个共享变量的原子性,注意是一个。多个变量时就不能保证原子性了
- ABA问题
有志者、事竟成,破釜沉舟,百二秦关终属楚;
苦心人、天不负,卧薪尝胆,三千越甲可吞吴.
加油吧,致每个正在奋斗路上的你!!!