CAS理解

文章目录
  1. 1. 比较并交换
  2. 2. CAS底层原理?如果知道,谈谈比对Unsafe的理解
    1. 2.1. Unsafe
    2. 2.2. CAS 是什么
  3. 3. CAS缺点

比较并交换

CAS底层原理?如果知道,谈谈比对Unsafe的理解

Unsafe

  1. Unsafe 是 CAS 的核心类,由于 Java 方法无法直接访问底层系统,需要通过本地(native)方法来访问,Unsafe 相当于一个后门,基于该类可以直接操作特定内存的数据。Unsafe 类存在于 sun.misc 包中,其内部方法操作可以像 C 的指针一样直接操作内存,因为 Java 中 CAS 操作的执行依赖于 Unsafe 类的方法。

    注意 Unsafe 类中的所有方法都是 native 修饰的,也就是说 Unsafe 类中的方法都直接调用操作系统底层资源执行相应任务。

  2. 变量 valueOffset,表示该变量在内存中的偏移地址,因为 Unsafe 就是根据内存偏移地址获取数据的。

  3. 变量 value 用 volatile 修饰,保证了多线程之间的内存可见性。

CAS 是什么

  1. unsafe.getAndAddInt

    假设线程 A 和线程 B 两个线程同时执行 getAndAddInt 操作(分别跑在不同 CPU 上)

    AtomicInteger 里面的 value 原始值为 3,即主内存中 AtomicInteger 的 value 为 3,根据 JMM 模型,线程 A 和线程 B 各自持有一份值为 3 的 value 的副本分别到各自的工作内存。

    线程 A 通过 getIntVolatile(var1,var2)拿到 value 值 3,这是线程 A 被挂起。

    线程 B 也通过 getIntVolatile(var1,var2)方法获得 value 值 3,此时刚好线程 B 没有被挂起并执行 compareAndSwap 方法比较内存值也为 3,成功修改内存值为 4,线程 B 打完收工,一切OK。

    这是线程 A 回复,执行 compareAndSwapInt 方法比较,发现手里的值 3 与内存值 4 不一致,说明该值已经被其他线程抢险异步修改过了,那 A 线程本次修改失败,只能重新读取重新来一遍了。

    线程 A 重新获取 value 值,因为变量 value 被 volatile 修饰,所以其他线程对它的修改,线程 A 总是能够看到,线程 A 继续执行 compareAndSwapInt 进行比较替换,直到成功。

  2. 底层汇编

  3. 简单版小总结
    CAS(CompareAndSwap)
    比较当前工作内存中的值和主内存中的值,如果相同则执行规定操作,否则继续比较知道主内存和工作内存中的值一致为止。

CAS应用
CAS有 3 个操作数,内存值 V,旧的预期值 A,要修改的更新值 B。
当且仅当预期值 A 和内存值 V 相同时,将内存值 V 修改为 B,否则什么都不做。

CAS缺点

  1. 循环时间长开销大
    如果 CAS 失败,会一直进行尝试。如果 CAS 长时间一直不成功,可能会给 CPU 带来很大的开销。

  2. 只能保证一个共享变量的原子操作
    当对一个共享变量执行操作时,我们只能使用循环 CAS 的方式来保证原子操作,但是,对多个共享变量操作时,循环 CAS 就无法保证操作的原子性,这个时候就可以用锁来保证原子性。

  3. 引出来 ABA 问题???
    通过原子引用解决 ABA 问题