JAVA 中的 CAS
原文地址:https://www.xilidou.com/2018/02/01/java-cas/
CAS 是现代操作系统,解决并发问题的一个重要手段,最近在看 eureka 的源码的时候。遇到了很多 CAS 的操作。今天就系统的回顾一下 Java 中的CAS。
阅读这篇文章你将会了解到:
- 什么是 CAS
 - CAS 实现原理是什么?
 - CAS 在现实中的应用
- 自旋锁
 - 原子类型
 - 限流器
 
 - CAS 的缺点
 
什么是 CAS
CAS: 全称Compare and swap,字面意思:”比较并交换“,一个 CAS 涉及到以下操作:
我们假设内存中的原数据V,旧的预期值A,需要修改的新值B。
- 比较 A 与 V 是否相等。(比较)
 - 如果比较相等,将 B 写入 V。(交换)
 - 返回操作是否成功。
 
当多个线程同时对某个资源进行CAS操作,只能有一个线程操作成功,但是并不会阻塞其他线程,其他线程只会收到操作失败的信号。可见 CAS 其实是一个乐观锁。
CAS 是怎么实现的
跟随AtomInteger的代码我们一路往下,就能发现最终调用的是 sum.misc.Unsafe 这个类。看名称 Unsafe 就是一个不安全的类,这个类是利用了 Java 的类和包在可见性的的规则中的一个恰到好处处的漏洞。Unsafe 这个类为了速度,在Java的安全标准上做出了一定的妥协。
再往下寻找我们发现 Unsafe的compareAndSwapInt 是 Native 的方法:
1  | public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);  | 
也就是说,这几个 CAS 的方法应该是使用了本地的方法。所以这几个方法的具体实现需要我们自己去 jdk 的源码中搜索。
于是我下载一个 OpenJdk 的源码继续向下探索,我们发现在 /jdk9u/hotspot/src/share/vm/unsafe.cpp 中有这样的代码:
1  | {CC "compareAndSetInt", CC "(" OBJ "J""I""I"")Z", FN_PTR(Unsafe_CompareAndSetInt)},  | 
这个涉及到,JNI 的调用,感兴趣的同学可以自行学习。我们搜索 Unsafe_CompareAndSetInt后发现:
1  | UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) {  | 
最终我们终于看到了核心代码 Atomic::cmpxchg。
继续向底层探索,在文件java/jdk9u/hotspot/src/os_cpu/linux_x86/vm/atomic_linux_x86.hpp有这样的代码:
1  | inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value, cmpxchg_memory_order order) {  | 
我们通过文件名可以知道,针对不同的操作系统,JVM...
剩余内容已隐藏