ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
[TOC] ## 简介 CAS是Compare-and-swap(比较与替换)的简写,是一种有名的无锁算法。 CAS指令需要三个操作数,分别是 * 内存地址(在Java内存模型中可以简单理解为主内存中变量的内存地址) * 旧值(在Java内存模型中,可以理解工作内存中缓存的主内存的变量的值) * 新值 CAS操作执行时,当且仅当主内存对应的值等于旧值时,处理器用新值去更新旧值,否则它就不执行更新。但是无论是否更新了主内存中的值,都会返回旧值,上述的处理过程是一个原子操作。 所谓的CAS自旋,指的就是如果执行一次CAS失败。那说明在执行“获取-设置”操作的时候值已经有了修改,那么旧值替换成内存地址的值,然后再次循环进行下一次操作,直到设置成功为止。 ## CAS在Java中的实现 Java程序中才可以使用CAS操作,该操作由sun.misc.Unsafe类里面的compareAndSwapInt和 compareAndSwapLong 等几个方法包装提供。 以AtomicInteger#incrementAndGet()为例子 ~~~ private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe(); private static final long VALUE; static { try { //AtomicInteger对象value成员变量在内存中的偏移量。我们可以简单地把valueOffset理解为value变量的内存地址。 VALUE = U.objectFieldOffset (AtomicLong.class.getDeclaredField("value")); } catch (ReflectiveOperationException e) { throw new Error(e); } } public final boolean compareAndSet(long expect, long update) { /** * 第一个参数object是当前对象 * 第二个参数offest表示该变量在内存中的偏移地址(CAS底层是根据内存偏移位置来获取的) * 第三个参数expected为旧值 * 第四个参数x为新值。 */ return U.compareAndSwapInt(this, VALUE, expect, update); } ~~~ 在java中,我们主要分析Unsafe类,因为所有的CAS操作都是它来实现的,在Unsafe类中这些方法也都是native方法 ~~~ public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5); public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5); public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6) ~~~ 由于Unsafe类不是提供给用户程序调用的类(Unsafe.getUnsafe()的代码中限制了只有启动类加载器(Bootstrap ClassLoader)加载的Class才能访问它)。因此,如果不采用反射手段,我们只能通过其他的Java API来间接使用它,如J.U.C包里面的整数原子类,其中的compareAndSet()和getAndIncrement()等方法都使用了Unsafe类的CAS操作。 ~~~ UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) { oop p = JNIHandles::resolve(obj); if (p == NULL) { volatile jint* addr = (volatile jint*)index_oop_from_field_offset_long(p, offset); return RawAccess<>::atomic_cmpxchg(x, addr, e) == e; } else { assert_field_offset_sane(p, offset); return HeapAccess<>::atomic_cmpxchg_at(x, p, (ptrdiff_t)offset, e) == e; } } UNSAFE_END ~~~ unsafe.cpp最终会调用atomic.cpp, 而atomic.cpp会根据不同的处理调用不同的处理器指令 ## 参考资料 [Java并发编程:CAS操作](https://blog.csdn.net/fei20121106/article/details/83186222)