unsafe中對應擁有三個方法 compareAndSwapObject
,compareAndSwapInt
和compareAndSwapLong
,他們都被標記爲nativehtml
它的核心實現爲java
oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e);
實現核心以下linux
inline oop oopDesc::atomic_compare_exchange_oop(oop exchange_value, volatile HeapWord *dest, oop compare_value) { if (UseCompressedOops) { narrowOop val = encode_heap_oop(exchange_value); narrowOop cmp = encode_heap_oop(compare_value); narrowOop old = (narrowOop) Atomic::cmpxchg(val, (narrowOop*)dest, cmp); return decode_heap_oop(old); } else { return (oop)Atomic::cmpxchg_ptr(exchange_value, (oop*)dest, compare_value); } }
UseCompressedOops: 32位平臺運行的程序在64位上會佔用更大的長度,可使用
-XX:+UserCompressedOops
壓縮指針,達到節約內存的目的。
核心代碼以下windows
return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
核心代碼以下架構
if (VM_Version::supports_cx8()) return (jlong)(Atomic::cmpxchg(x, addr, e)) == e; else { jboolean success = false; ObjectLocker ol(p, THREAD); if (*addr == e) { *addr = x; success = true; } return success; }
supports_cx8:判斷硬件是否是支持8-byte compare-exchange
, x86架構中經過cpuid
指令來獲取是否試支持,CMPXCHG8
指令 ;SPARC架構也是看 (_features & v9_instructions_m)
指令的支持狀況函數
不管是那個調用,最終都歸結到了Atomic上,Atomic.hpp中函數聲明以下oop
//比較當前的值和目的地址的值,若是比較成功,就把目的地址的值更改成exchange_value,並返回原來存的值 static jbyte cmpxchg (jbyte exchange_value, volatile jbyte* dest, jbyte compare_value); static jint cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value); static jlong cmpxchg (jlong exchange_value, volatile jlong* dest, jlong compare_value); static unsigned int cmpxchg(unsigned int exchange_value, volatile unsigned int* dest, unsigned int compare_value); static intptr_t cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value); static void* cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value);
從Atomic.cpp能夠看到在不一樣的操做系統中有不一樣的實現
在 windows_x86中,一種實現以下ui
inline jint Atomic::cmpxchg (jint exchange_value, volatile jint* dest, jint compare_value) { 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 } }
linux_x86中,實現以下atom
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; }
能夠看到最終都是使用操做系統對應的指令來完成spa
能夠看到Atomic的實現就是用的CAS
,好比AtomicInteger
的incrementAndGet
public final int incrementAndGet() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return next; } }
這種一直循環的操做也稱做自旋
AtomicStampedReference
來解決這個問題,原理是添加一個額外的版原本作判斷源碼來自jdk1.7