CAS的底层原理是什么

参考答案

1.  CAS(compareAndSwap)的概念

前往查看:什么是CAS

2.  CAS的优点、缺点

前往查看:CAS有什么优点、缺点

3.  CAS的底层原理

CAS的实现主要在JUC中的atomic包,我们以AtomicInteger类为例:

CAS的底层原理是什么

通过代码追溯,可见:

Java中的CAS操作,都是通过sun包下Unsafe类实现。

而Unsafe类中的方法都是native方法,由JVM本地实现,所以最终的实现是基于C、C++在操作系统之上操作。

CAS的底层原理是什么

Unsafe类,在sun.misc包下,不属于Java标准。

Unsafe类提供一系列增加Java语言能力的操作,如内存管理、操作类/对象/变量、多线程同步等。

//var1为CAS操作的对象,offset为var1某个属性的地址偏移值,expected为期望值,var2为要设置的值,利用JNI来完成CPU指令的操作
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);
public native Object getObjectVolatile(Object var1, long var2);
public native void putObjectVolatile(Object var1, long var2, Object var4);
Hotspot源码中关于unsafe的实现hotspot\src\share\vm\prims\unsafe.cpp
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
 UnsafeWrapper("Unsafe_CompareAndSwapInt");
 oop p = JNIHandles::resolve(obj);根据偏移量,计算value的地址。这里的offset就是 AtomaicInteger中的valueOffset
 jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
 return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
UNSAFE_END\hotspot\src\share\vm\runtime\atomic.cppunsigned Atomic::cmpxchg(unsigned int exchange_value,
             volatile unsigned int* dest, unsigned int compare_value) {
 assert(sizeof(unsigned int) == sizeof(jint), "more work to do");
 return (unsigned int)Atomic::cmpxchg((jint)exchange_value, (volatile jint*)dest,
                    (jint)compare_value);
}根据操作系统类型调用不同平台下的重载函数,这个在预编译期间编译器会决定调用哪个平台下的重载

调用了“Atomic::cmpxchg”方法,“Atomic::cmpxchg”方法在linux_x86和windows_x86的实现如下:

linux_x86底层实现\hotspot\src\os_cpu\linux_x86\vm\atomic_linux_x86.inline.hpp
inline jint   Atomic::cmpxchg  (jint   exchange_value, volatile jint*   dest, jint   compare_value) {
 int mp = os::is_MP();
 __asm__ volatile (LOCK_IF_MP(%4) "cmpxchgl %1,(%3)"
          : "=a" (exchange_value)
          : "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
          : "cc", "memory");
 return exchange_value;
}
windows_x86底层实现
hotspot\src\os_cpu\windows_x86\vmatomic_linux_x86.inline.hpp
inline jint   Atomic::cmpxchg  (jint   exchange_value, volatile jint*   dest, jint   compare_value) {
 // alternative for InterlockedCompareExchange
 int mp = os::is_MP();
 __asm {
  mov edx, dest
  mov ecx, exchange_value
  mov eax, compare_value
  LOCK_IF_MP(mp)
  cmpxchg dword ptr [edx], ecx
 }
}

CAS底层实现根据不同的操作系统会有不同重载,CAS的实现离不开处理器的支持。

核心代码就是一条带lock 前缀的 cmpxchg 指令,即lock cmpxchg dword ptr [edx], ecx

Atomic::cmpxchg方法解析:

  • mp是“os::is_MP()”的返回结果,“os::is_MP()”是一个内联函数,用来判断当前系统是否为多处理器。如果当前系统是多处理器,该函数返回1;否则,返回0。
  • LOCK_IF_MP(mp)会根据mp的值来决定是否为cmpxchg指令添加lock前缀。如果通过mp判断当前系统是多处理器(即mp值为1),则为cmpxchg指令添加lock前缀;否则,不加lock前缀。

这是一种优化手段,认为单处理器的环境没有必要添加lock前缀,只有在多核情况下才会添加lock前缀,因为lock会导致性能下降。cmpxchg是汇编指令,作用是比较并交换操作数。

以上,是Java面试题【 CAS的底层原理是什么】的参考答案。

 

输出,是最好的学习方法

欢迎在评论区留下你的问题、笔记或知识点补充~

—end—

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧