CAS
一、什么是CAS
-
概念
CAS(compare and swap)即比较并交换。它是解决多线程的环境下使用锁造成性能损耗的一种机制。
-
内容
- CAS操作一般包含三个操作数——内存位置(V)、预期原值(A)和新值(B)
- 当且仅当预期值A和内存值V相同时,将内存值修改为B并返回true,否则什么都不做并返回false
-
原理
- CAS通过调用JNI的代码实现的。JNI:Java Native Interface为JAVA本地调用,允许java调用其他语言
- 借助C来调用CPU底层指令实现的
- 当前的处理器基本都支持CAS,只不过不同的厂家的实现不一样
二、CAS在Java中应用
-
Unsafe
-
Unsafe类是CAS的核心类,提供硬件级别的原子操作。
-
JUC中大量使用了sun.misc.Unsafe 这个类,但是却不建议开发者使用(官方)
- Unsafe有可能在未来的Jdk版本移除或者不允许Java应用代码使用,这一点可能导致使用了Unsafe的应用无法运行在高版本的Jdk
- Unsafe的不少方法中必须提供原始地址(内存地址)和被替换对象的地址,偏移量要自己计算,一旦出现问题就是JVM崩溃级别的异常,会导致整个JVM实例崩溃,表现为应用程序直接crash掉
- Unsafe提供的直接内存访问的方法中使用的内存不受JVM管理(无法被GC),需要手动管理,一旦出现疏忽很有可能成为内存泄漏的源头
Unsafe在JUC(java.util.concurrent)包中大量使用(主要是CAS),在netty中方便使用直接内存,还有一些高并发的交易系统为了提高CAS的效率也有可能直接使用到Unsafe。总而言之,Unsafe类是一把双刃剑,所以要慎用。
-
作用:内存管理、多线程同步、线程的挂起和恢复、内存屏障、其他(如获取系统的平均负载值、绕过检测机制直接抛出异常)
-
更多关于Unsafe类本地的原理的解析,请参考 Java中神奇的双刃剑-Unsafe,写的很很推荐
-
-
缺点
-
开销大
并发量比较高的情况下,如果反复尝试更新某个变量,却又一直更新不成功,会给CPU带来较大的压力
-
不能保证代码块的原子性
只能保证一个变量的原子性操作,而多个方法或者代码块之的原子性则无法保证。
-
ABA问题
当变量从A修改为B在修改回A时,变量值等于期望值A,但是无法判断是否修改,CAS操作在ABA修改后依然成功。
java.util.concurrent包为了解决这个问题,提供了一个带有标记的原子引用类"AtomicStampedReference",它可以通过控制变量值的版本来保证CAS的正确性。
不过目前来说这个类比较"鸡肋",大部分情况下ABA问题并不会影响程序并发的正确性,如果需要解决ABA问题,使用传统的互斥同步可能回避原子类更加高效。
-