monsterhxw / my-notes

技术随想
MIT License
2 stars 0 forks source link

Java CAS 的原理 #8

Open monsterhxw opened 5 months ago

monsterhxw commented 5 months ago

Java 的 CAS 调用的是 Unsafe 类的 native 方法

源码: https://github.com/openjdk/jdk8u/blob/master/jdk/src/share/classes/sun/misc/Unsafe.java#L885-L887

public final native boolean compareAndSwapInt(Object o, long offset,
                                              int expected,
                                              int x);

Unsafe 的 compareAndSwapInt 的 native 方法实现

源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/prims/unsafe.cpp#L1213-L1218

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);
    jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
    return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
UNSAFE_END

Atomic::cmpxchg 方法的实现

源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/share/vm/runtime/atomic.cpp#L70-L75

unsigned 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 方法,对应的操作系统 (Linux) 和指令集 (x86) 的具体实现

源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp#L93-L100

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;
}

根据上面的代码得到对应的汇编代码

movl 0xc(%rbx), %ebx       ; 从 rbx 寄存器加上偏移量 0xc 的内存的值 (dest 的内存地址),存入 edx 寄存器
movl 0x8(%r11), %ecx       ; 加载 exchange_value 内存值到 ecx 寄存器
movl 0xc(%r11), %eax       ; 加载 compare_value 内存值到 eax 寄存器
lock cmpxchgl %ecx, (%ebx) ; lock 指令 (锁总线,确保原子),将脏缓存写回内存
                           ; cmpxchgl 指令,比较 eax 寄存器中的值和 ebx 所指向内存的位置存储的值是否相等
                           ; 相等,将 ecx 寄存器的值存入 ebx 寄存器所指向的内存位置
                           ; 不等,将 ebx 寄存器所指向内存位置中的值存到 eax 寄存器中,作为返回

Atomic::cmpxchg 方法,Windows OS 和指令集 (x86) 的具体实现

源码比较直观

源码: https://github.com/openjdk/jdk8u/blob/master/hotspot/src/os_cpu/windows_x86/vm/atomic_windows_x86.inline.hpp#L216-L226

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
    }
}

Refs