摘要:中對應擁有三個方法和,他們都被標記為它的核心實現為實現核心如下位平臺運行的程序在位上會占用更大的長度,可以使用壓縮指針,達到節約內存的目的。只能是一個變量問題。自身提供了來解決這個問題,原理是添加一個額外的版本來做判斷源碼來自
unsafe中對應擁有三個方法 compareAndSwapObject ,compareAndSwapInt和compareAndSwapLong ,他們都被標記為native
compareAndSwapObject它的核心實現為
oop res = oopDesc::atomic_compare_exchange_oop(x, addr, e);
實現核心如下
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壓縮指針,達到節約內存的目的。compareAndSwapInt
核心代碼如下
return (jint)(Atomic::cmpxchg(x, addr, e)) == e;compareAndSwapLong
核心代碼如下
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::cmpxchg無論是那個調用,最終都歸結到了Atomic上,Atomic.hpp中函數聲明如下
//比較當前的值和目的地址的值,如果比較成功,就把目的地址的值更改為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中,一種實現如下
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中,實現如下
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; }
可以看到最終都是使用操作系統對應的指令來完成
都在哪兒用了
可以看到Atomic的實現就是用的CAS,比如AtomicInteger的incrementAndGet
public final int incrementAndGet() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return next; } }
這種一直循環的操作也稱作自旋
CAS的缺點如果一直沒有成功,則一直循環,給CPU帶來很大的開銷。
只能是一個變量
ABA問題。一個變量取值為A,恰巧另一個線程將它換成了B然后又換回來了,這個時候再讀取還是A,實際上是改變了值。java自身提供了AtomicStampedReference來解決這個問題,原理是添加一個額外的版本來做判斷
源碼來自jdk1.7
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/72727.html
摘要:方法由兩個參數,表示期望的值,表示要給設置的新值。操作包含三個操作數內存位置預期原值和新值。如果處的值尚未同時更改,則操作成功。中就使用了這樣的操作。上面操作還有一點是將事務范圍縮小了,也提升了系統并發處理的性能。 這是java高并發系列第21篇文章。 本文主要內容 從網站計數器實現中一步步引出CAS操作 介紹java中的CAS及CAS可能存在的問題 悲觀鎖和樂觀鎖的一些介紹及數據庫...
摘要:耐心看完的你或多或少會有收獲并發的核心就是包,而的核心是抽象隊列同步器,簡稱,一些鎖啊信號量啊循環屏障啊都是基于。 耐心看完的你或多或少會有收獲! Java并發的核心就是 java.util.concurrent 包,而 j.u.c 的核心是AbstractQueuedSynchronizer抽象隊列同步器,簡稱 AQS,一些鎖啊!信號量啊!循環屏障啊!都是基于AQS。而 AQS 又是...
摘要:這個規則比較好理解,無論是在單線程環境還是多線程環境,一個鎖處于被鎖定狀態,那么必須先執行操作后面才能進行操作。線程啟動規則獨享的方法先行于此線程的每一個動作。 1. 指令重排序 關于指令重排序的概念,比較復雜,不好理解。我們從一個例子分析: public class SimpleHappenBefore { /** 這是一個驗證結果的變量 */ private st...
摘要:有了這個基礎,才能發揮作用,使得在節點取消和異常時能夠保證隊列在多線程下的完整性。 Doug Lea是JDK中concurrent工具包的作者,這位大神是誰可以自行google。 本文淺析ReentrantLock(可重入鎖)的原理 Lock接口 showImg(https://segmentfault.com/img/bV2671?w=276&h=176); Lock接口定義了這幾個...
閱讀 1982·2019-08-30 15:54
閱讀 3532·2019-08-30 15:52
閱讀 1822·2019-08-29 17:20
閱讀 2513·2019-08-29 17:08
閱讀 2346·2019-08-26 13:24
閱讀 780·2019-08-26 11:59
閱讀 2780·2019-08-23 14:50
閱讀 611·2019-08-23 14:20