JDK 1.8 sun.misc.Unsafe類CAS底層實現

在java.util.concurrent包下面的不少類爲了追求性能都採用了sun.misc.Unsafe類中的CAS操做,從而避免使用synchronized等加鎖方式帶來性能上的不足。html

在sun.misc.Unsafe中CAS方法以下:java

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)。app

這三個方法都是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操做。oop

繼續深刻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)函數雖然有不少重載函數,但最終都是調用的下面的函數:ui

 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)函數在不一樣系統中都有各自的聲明,可是最終都是調用的下面的函數:this

 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\n\t"
29        "je 1f \n\t"
30        "lock\n\t"
31        "1: cmpxchg8b (%%edi)\n\t"
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指令實現方式。atom

從上面能夠看出不管是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

相關文章
相關標籤/搜索