
比较并交换
CAS底层原理?如果知道,谈谈比对Unsafe的理解
Unsafe
-
Unsafe 是 CAS 的核心类,由于 Java 方法无法直接访问底层系统,需要通过本地(native)方法来访问,Unsafe 相当于一个后门,基于该类可以直接操作特定内存的数据。Unsafe 类存在于 sun.misc 包中,其内部方法操作可以像 C 的指针一样直接操作内存,因为 Java 中 CAS 操作的执行依赖于 Unsafe 类的方法。
注意 Unsafe 类中的所有方法都是 native 修饰的,也就是说 Unsafe 类中的方法都直接调用操作系统底层资源执行相应任务。
-
变量 valueOffset,表示该变量在内存中的偏移地址,因为 Unsafe 就是根据内存偏移地址获取数据的。
-
变量 value 用 volatile 修饰,保证了多线程之间的内存可见性。
CAS 是什么
-
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 进行比较替换,直到成功。
-
底层汇编
-
简单版小总结
CAS(CompareAndSwap)
比较当前工作内存中的值和主内存中的值,如果相同则执行规定操作,否则继续比较知道主内存和工作内存中的值一致为止。
CAS应用
CAS有 3 个操作数,内存值 V,旧的预期值 A,要修改的更新值 B。
当且仅当预期值 A 和内存值 V 相同时,将内存值 V 修改为 B,否则什么都不做。
CAS缺点
-
循环时间长开销大
如果 CAS 失败,会一直进行尝试。如果 CAS 长时间一直不成功,可能会给 CPU 带来很大的开销。 -
只能保证一个共享变量的原子操作
当对一个共享变量执行操作时,我们只能使用循环 CAS 的方式来保证原子操作,但是,对多个共享变量操作时,循环 CAS 就无法保证操作的原子性,这个时候就可以用锁来保证原子性。 -
引出来 ABA 问题???
通过原子引用解决 ABA 问题




近期评论