标签:学习二 应用 自增 是什么 直接 i++ 共享 本地 不成功
讲解线路:
CAS-->UnSafe-->CAS底层思想-->ABA-->原子引用更新-->如何规避ABA问题
CAS的全称为Compare-And-Swap,即比较并交换,它是一条CPU并发原语。它的功能是判断内存某个位置的值是否为预期值,如果是则更改为新的值,这个过程是原子的。
CAS并发原语体现在JAVA语言中就是sun.misc.Unsafe类中的各个方法。调用UnSafe类中的CAS方法,JVM会帮我们实现出CAS汇编指令。这是一种完全依赖于硬件的功能,通过它实现了原子操作。再次强调,由于CAS是一种系统原语,原语属于操作系统用语范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题。
我们先来看看AtomicInteger源码,我们知道了AtomicInteger原子变量通过了用volatile修饰变量保证内存可见性,CAS(Compare-And-Swap)算法保证数据的原子性。
我们看AtomicInteger中的getAndIncrement方法,其作用相当于i++,先取i的值,再自增一。它能在多线程的环境下保持数据原子性。它调用了UnSafe类的CompareAndSwapInt方法,this为当前AtomicInteger对象,valueOffeset为该变量值在内存中的偏移地址,因为UnSafe就是通过内存偏移地址获取数据。
var5为当前对象和内存偏移地址就可以获取当前物理内存值作为副本,然后再判断内存值与预期值,相等值加一,修改成功则跳出循环,否则一直自旋。
Unsafe类是CAS的核心类,由于java方法无法直接访问底层系统,需要通过本地(native)方法来访问,Unsafe相当于一个后门吧,基于该类可以直接操作特定内存的数据。Unsafe类存在于sun.misc包中,其内部方法操作可以像C的指针一样直接操作内存,因为java中CAS操作的执行依赖于Unsafe类的方法。CAS底层靠的是Unsafe这个类来保证原子性。
注意:Unsafe类中的所有方法都是native修饰的,也就是说Unsafe类中的方法都是直接调用操作系统底层资源执行相应任务。
比较当前工作内存中的值和主内存中的值,如果相同则执行规定操作,否则继续比较直到主内存和工作内存的值一致为止。
CAS底层原理
Unsafe类+CAS思想(自旋)
CAS应用
CAS有三个操作数,内存值V,旧的预期值A,要修改的更新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。
CAS缺点
1.循环时间长,开销大
我们可以看到getAndAddInt方法执行时,有个do while。如果CAS比较失败,会一直进行尝试。如果CAS长时间一直不成功,可能会给CPU带来很大的开销。
2.只能保证一个共享变量的原子操作
当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁来保证原子性。
3.引出ABA问题???
标签:学习二 应用 自增 是什么 直接 i++ 共享 本地 不成功
原文地址:https://www.cnblogs.com/mabaoying/p/13087143.html