what
CAS全称是compare and swap,将内存中的值和一个给定的值对比,如果相等该内存的值修改为给定的新值。注意这一步是属于原子操作。
how
通过简单的例子看一下本质,版本是jdk8:
1 | public class Test { |
直接看AtomicInteger.java代码
1 | /** |
看下unsafe变量:
1 | // setup to use Unsafe.compareAndSwapInt for updates |
跳转到Unsafe.java的getAndAddInt方法
1 | /** |
跳转到getIntVolatile方法
1 | /** Volatile version of {@link #getInt(Object, long)} */ |
很明显getIntVolatile的作用是获取给定地址的值。接下来看compareAndSwapInt方法
1 | /** |
我们直接到UnSafe.cpp类查找compareAndSwapInt
1 |
|
compareAndSwapInt会出现在多处,我们选择methods_18,因为是jdk8。然后搜索methods_18
1 | // This one function is exported, used by NativeLookup. |
根据注释直接查找NativeLookup.cpp,搜索JVM_RegisterUnsafeMethods
1 |
|
这样我们就找到了Java_sun_misc_Unsafe_registerNatives,其实就是指Java_sun_misc_Unsafe_registerNatives对应JVM_RegisterPerfMethods,而Java_sun_misc_Unsafe_registerNatives根据命名知道在Unsafe.java中。
1 | private static native void registerNatives(); |
即在Unsafe加载之后就会调用registerNatives,即调用JVM_RegisterUnsafeMethods,即调用了Unsafe.cpp的register_natives
1 | /** |
即注册了对应的方法。即compareAndSwapInt对应Unsafe_CompareAndSwapInt方法
1 | UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) |
直接看Atomic.cpp的cmpxchg方法
1 | unsigned Atomic::cmpxchg(unsigned int exchange_value, |
在runtime/atomic.inline.hpp可以知道有很多不同版本的cmpxchg实现
1 | /* |
本来想看arm平台的,没找到,最后看atomic_linux_x86.inline.hpp的,
1 | inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value) { |
由于篇幅已经够长了,因此开了一篇新文章,用以解释上面的代码,推荐看下那篇文章,这里直接告诉结果:
%1表示exchange_value,%3表示dest,这里”a” (compare_value)将compare_value的值赋给eax寄存器,这里cmpxchgl的指令作用是比较compare_value和dest的值,如果相等,将exchange_value赋值给dest,如果不相等,将dest的值赋值给exchange_value。而Unsafe_CompareAndSwapInt方法,返回值是cmpxchgl的返回值和e比较,不相等时,一直跑循环,否则,退出。这样就完成了原子自增操作。