zoukankan      html  css  js  c++  java
  • JDK 1.8 sun.misc.Unsafe类CAS底层实现

    在java.util.concurrent包下面的很多类为了追求性能都采用了sun.misc.Unsafe类中的CAS操作,从而避免使用synchronized等加锁方式带来性能上的不足。

    在sun.misc.Unsafe中CAS方法如下:

    1     public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
    2 
    3     public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
    4 
    5     public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

    在JDK1.8中只有上述三个CAS方法,其方法参数含义为:var1为待修改的field对象;var2为field对象偏移量,为long型;var4为期望值;var5或var6为替换值,当var1[offset] == var4则设置var1[offset] = var5(var6)。

    这三个方法都是native方法,可以查看hotspot源码查看其底层实现:(hotspot/src/share/vm/prims/unsafe.cpp)

    1 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
    2 
    3 {CC"compareAndSwapObject", CC"("OBJ"J"OBJ""OBJ")Z",  FN_PTR(Unsafe_CompareAndSwapObject)},
    4 {CC"compareAndSwapInt",  CC"("OBJ"J""I""I"")Z",      FN_PTR(Unsafe_CompareAndSwapInt)},
    5 {CC"compareAndSwapLong", CC"("OBJ"J""J""J"")Z",      FN_PTR(Unsafe_CompareAndSwapLong)},
     1 UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject e_h, jobject x_h))
     2   UnsafeWrapper("Unsafe_CompareAndSwapObject");
     3   oop x = JNIHandles::resolve(x_h); // 更新值
     4   oop e = JNIHandles::resolve(e_h); // 期望值
     5   oop p = JNIHandles::resolve(obj); // 更新对象
     6   HeapWord* addr = (HeapWord *)index_oop_from_field_offset_long(p, offset); // 根据偏移量offset获取内存中的具体位置
     7   oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e, true); // 调用方法执行CAS操作
     8   jboolean success  = (res == e);  // 如果返回值res==e则表明满足compare条件,swap成功
     9   if (success)
    10     update_barrier_set((void*)addr, x); // 更新memory barrier
    11   return success;
    12 UNSAFE_END
    13 
    14 UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
    15   UnsafeWrapper("Unsafe_CompareAndSwapInt");
    16   oop p = JNIHandles::resolve(obj);
    17   jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
    18   return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
    19 UNSAFE_END
    20 
    21 UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong e, jlong x))
    22   UnsafeWrapper("Unsafe_CompareAndSwapLong");
    23   Handle p (THREAD, JNIHandles::resolve(obj));
    24   jlong* addr = (jlong*)(index_oop_from_field_offset_long(p(), offset));
    25   if (VM_Version::supports_cx8())
    26     return (jlong)(Atomic::cmpxchg(x, addr, e)) == e;
    27   else {
    28     jboolean success = false;
    29     ObjectLocker ol(p, THREAD);
    30     if (*addr == e) { *addr = x; success = true; }
    31     return success;
    32   }
    33 UNSAFE_END

    先来看下Unsafe_CompareAndSwapObject方法,该方法通过调用index_oop_from_field_offset_long方法找到需要执行CAS对象的具体地址,然后调用atomic_compare_exchange_oop方法执行CAS操作。

    继续深入atomic_compare_exchange_oop方法看一下,源码如下

     1 // 声明在hotspot/src/share/vm/oops/oop.hpp
     2 static oop atomic_compare_exchange_oop(oop exchange_value,
     3                                        volatile HeapWord *dest,
     4                                        oop compare_value,
     5                                        bool prebarrier = false);
     6 
     7 // 定义在hotspot/src/share/vm/oops/oop.inline.hpp
     8 inline oop oopDesc::atomic_compare_exchange_oop(oop exchange_value,
     9                                                 volatile HeapWord *dest,
    10                                                 oop compare_value,
    11                                                 bool prebarrier) {
    12   if (UseCompressedOops) {
    13     if (prebarrier) {
    14       update_barrier_set_pre((narrowOop*)dest, exchange_value);
    15     }
    16     // encode exchange and compare value from oop to T
    17     narrowOop val = encode_heap_oop(exchange_value);
    18     narrowOop cmp = encode_heap_oop(compare_value);
    19 
    20     narrowOop old = (narrowOop) Atomic::cmpxchg(val, (narrowOop*)dest, cmp);
    21     // decode old from T to oop
    22     return decode_heap_oop(old);
    23   } else {
    24     if (prebarrier) {
    25       update_barrier_set_pre((oop*)dest, exchange_value);
    26     }
    27     return (oop)Atomic::cmpxchg_ptr(exchange_value, (oop*)dest, compare_value);
    28   }
    29 }

    在atomic_compare_exchange_oop方法中,核心的CAS操作最终是调用了Atomic::cmpxchg(val, (narrowOop*)dest, cmp)函数或者Atomic::cmpxchg_ptr(exchange_value, (oop*)dest, compare_value)函数。

     Atomic::cmpxchg(val, (narrowOop*)dest, cmp)函数虽然有很多重载函数,但最终都是调用的下面的函数:

     1 // hotspot/src/share/vm/runtime/Atomic.cpp
     2 jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value) {
     3   assert(sizeof(jbyte) == 1, "assumption.");
     4   uintptr_t dest_addr = (uintptr_t)dest;
     5   uintptr_t offset = dest_addr % sizeof(jint);
     6   volatile jint* dest_int = (volatile jint*)(dest_addr - offset);
     7   jint cur = *dest_int; // 对象当前值
     8   jbyte* cur_as_bytes = (jbyte*)(&cur);  // 当前值cur的地址
     9   jint new_val = cur;
    10   jbyte* new_val_as_bytes = (jbyte*)(&new_val);  // new_val地址
    11   // new_val存exchange_value,后面修改则直接从new_val中取值
    12   new_val_as_bytes[offset] = exchange_value;
    13   // 比较当前值与期望值,如果相同则更新,不同则直接返回
    14   while (cur_as_bytes[offset] == compare_value) {
    15     // 调用汇编指令cmpxchg执行CAS操作,期望值为cur,更新值为new_val
    16     jint res = cmpxchg(new_val, dest_int, cur);
    17     if (res == cur) break;
    18     cur = res;
    19     new_val = cur;
    20     new_val_as_bytes[offset] = exchange_value;
    21   }
    22   // 返回当前值
    23   return cur_as_bytes[offset];
    24 }

    Atomic::cmpxchg_ptr(exchange_value, (oop*)dest, compare_value)函数在不同系统中都有各自的声明,但是最终都是调用的下面的函数:

     1 // hotspot/src/os_cpu/solaris_x86/vm/Atomic_solaris_x86.inline.hpp
     2 
     3   // This is the interface to the atomic instruction in solaris_i486.s.
     4   jlong _Atomic_cmpxchg_long_gcc(jlong exchange_value, volatile jlong* dest, jlong compare_value, int mp);
     5 
     6   inline jlong _Atomic_cmpxchg_long(jlong exchange_value, volatile jlong* dest, jlong compare_value, int mp) {
     7 #ifdef AMD64
     8     __asm__ __volatile__ (LOCK_IF_MP(%4) "cmpxchgq %1,(%3)"
     9                         : "=a" (exchange_value)
    10                         : "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
    11                         : "cc", "memory");
    12     return exchange_value;
    13 #else
    14     return _Atomic_cmpxchg_long_gcc(exchange_value, dest, compare_value, os::is_MP());
    15 
    16     #if 0
    17     // The code below does not work presumably because of the bug in gcc
    18     // The error message says:
    19     //   can't find a register in class BREG while reloading asm
    20     // However I want to save this code and later replace _Atomic_cmpxchg_long_gcc
    21     // with such inline asm code:
    22 
    23     volatile jlong_accessor evl, cvl, rv;
    24     evl.long_value = exchange_value;
    25     cvl.long_value = compare_value;
    26     int mp = os::is_MP();
    27 
    28     __asm__ volatile ("cmp $0, %%esi
    	"
    29        "je 1f 
    	"
    30        "lock
    	"
    31        "1: cmpxchg8b (%%edi)
    	"
    32        : "=a"(cvl.words[0]),   "=d"(cvl.words[1])
    33        : "a"(cvl.words[0]), "d"(cvl.words[1]),
    34          "b"(evl.words[0]), "c"(evl.words[1]),
    35          "D"(dest), "S"(mp)
    36        :  "cc", "memory");
    37     return cvl.long_value;
    38     #endif // if 0
    39 #endif // AMD64
    40   }

    在这个方法中废弃了32位系统的cmpxchg8b指令实现CAS操作方式,只提供了AMD64位操作系统cmpxchgq指令实现方式。

    从上面可以看出无论是Atomic::cmpxchg(val, (narrowOop*)dest, cmp)函数或者Atomic::cmpxchg_ptr(exchange_value, (oop*)dest, compare_value)函数,二者最终都是通过一条汇编指令实现CAS操作的。

    Unsafe_CompareAndSwapInt和Unsafe_CompareAndSwapLong两个方法都是调用Atomic::cmpxchg(val, (narrowOop*)dest, cmp)函数实现的,这个函数上面已经解释过。

    综合上面的源码分析,可以知道sun.misc.Unsafe类中的CAS都是通过一条汇编指令实现的,这也就不难理解为什么这个操作可以保证原子性了。

    参考文章:

    http://blog.csdn.net/qqqqq1993qqqqq/article/details/75211993

    https://www.cnblogs.com/dennyzhangdd/p/6734933.html

  • 相关阅读:
    Key-Value Memory Network
    Deep Mask Memory Network with Semantic Dependency and Context Moment for Aspect Level Sentiment Clas
    Deep Memory Network在Aspect Based Sentiment方向上的应用
    Deep Memory Network 深度记忆网络
    Self Attention 自注意力机制
    Attention基本公式及其变种
    *端策略优化算法(PPO)
    Policy Gradient 算法
    一本通 农场派对
    A
  • 原文地址:https://www.cnblogs.com/snowater/p/8303698.html
Copyright © 2011-2022 走看看