并發(fā)編程之CAS(Compare and Swap)原理

java.util.concurrent包完全建立在CAS之上诲宇。

AQS孩革,非阻塞數(shù)據(jù)結(jié)構(gòu)和原子變量類(java.util.concurrent.atomic包中的類),這些concurrent包中的基礎類都是使用這種模式來實現(xiàn)的得运,而concurrent包中的高層類又是依賴于這些基礎類來實現(xiàn)的膝蜈。從整體來看,concurrent包的實現(xiàn)示意圖如下:

concurrent包的實現(xiàn)

CAS

Compare and Swap

java.util.concurrent包中借助CAS實現(xiàn)了區(qū)別于synchronized同步鎖的一種樂觀鎖熔掺。

CAS應用
CAS有3個操作數(shù)饱搏,內(nèi)存值V,舊的預期值A置逻,要修改的新值B推沸。當且僅當預期值A和內(nèi)存值V相同時,將內(nèi)存值V修改為B,否則什么都不做鬓催。

非阻塞算法(nonblocking algorithms)
一個線程的失敗或者掛起不應該影響其他線程的失敗或掛起的算法肺素。

現(xiàn)代的CPU提供了特殊的指令,可以自動更新共享數(shù)據(jù)宇驾,而且能夠檢測到其他線程的干擾倍靡,而 compareAndSet() 就用這些代替了鎖定。

拿出AtomicInteger來研究在沒有鎖的情況下是如何做到數(shù)據(jù)正確性的课舍。

private volatile int value;

在沒有鎖的機制下可能需要借助volatile原語塌西,保證線程間的數(shù)據(jù)是可見的(共享的)。

這樣才獲取變量的值的時候才能直接讀取筝尾。

public final int get() {        return value;    }

然后來看看++i是怎么做到的捡需。

public final int incrementAndGet() {    
for (;;) {
        int current = get();
        int next = current + 1; 
        if (compareAndSet(current, next))
        return next;    
}
}

在這里采用了CAS操作,每次從內(nèi)存中讀取數(shù)據(jù)然后將此數(shù)據(jù)和+1后的結(jié)果進行CAS操作筹淫,如果成功就返回結(jié)果站辉,否則重試直到成功為止。

而compareAndSet利用JNI來完成CPU指令的操作贸街。

public final boolean compareAndSet(int expect, int update) {
       return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

整體的過程就是這樣子的庵寞,利用CPU的CAS指令,同時借助JNI來完成Java的非阻塞算法薛匪。其它原子操作都是利用類似的特性完成的捐川。

其中

unsafe.compareAndSwapInt(this, valueOffset, expect, update);

類似:
if (this == expect) {
this = update
return true;
} else {
return false;
}

那么問題就來了,成功過程中需要2個步驟:比較this == expect逸尖,替換this = update古沥,compareAndSwapInt如何這兩個步驟的原子性呢? 參考CAS的原理娇跟。

CAS原理
CAS通過調(diào)用JNI的代碼實現(xiàn)的岩齿。JNI:Java Native Interface為JAVA本地調(diào)用,允許java調(diào)用其他語言苞俘。
而compareAndSwapInt就是借助C來調(diào)用CPU底層指令實現(xiàn)的盹沈。
下面從分析比較常用的CPU(intel x86)來解釋CAS的實現(xiàn)原理。
下面是sun.misc.Unsafe類的compareAndSwapInt()方法的源代碼:
public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);

可以看到這是個本地方法調(diào)用吃谣。這個本地方法在openjdk中依次調(diào)用的c++代碼為:unsafe.cpp乞封,atomic.cpp和atomicwindowsx86.inline.hpp。這個本地方法的最終實現(xiàn)在openjdk的如下位置:openjdk-7-fcs-src-b147-27jun2011\openjdk\hotspot\src\oscpu\windowsx86\vm\ atomicwindowsx86.inline.hpp(對應于windows操作系統(tǒng)肃晚,X86處理器)拧廊。下面是對應于intel x86處理器的源代碼的片段:

// Adding a lock prefix to an instruction on MP machine// VC++ doesn't like the lock prefix to be on a single line// so we can't insert a label after the lock prefix.// By emitting a lock prefix, we can define a label after it.#define LOCK_IF_MP(mp) __asm cmp mp, 0 \ __asm je L0 \ __asm _emit 0xF0 \ __asm L0: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 }}
如上面源代碼所示滤港,程序會根據(jù)當前處理器的類型來決定是否為cmpxchg指令添加lock前綴著榴。如果程序是在多處理器上運行脑又,就為cmpxchg指令加上lock前綴(lock cmpxchg)。反之,如果程序是在單處理器上運行,就省略lock前綴(單處理器自身會維護單處理器內(nèi)的順序一致性,不需要lock前綴提供的內(nèi)存屏障效果)。

intel的手冊對lock前綴的說明如下:
確保對內(nèi)存的讀-改-寫操作原子執(zhí)行。在Pentium及Pentium之前的處理器中秧了,帶有l(wèi)ock前綴的指令在執(zhí)行期間會鎖住總線帝嗡,使得其他處理器暫時無法通過總線訪問內(nèi)存。很顯然,這會帶來昂貴的開銷。從Pentium 4谦絮,Intel Xeon及P6處理器開始赠潦,intel在原有總線鎖的基礎上做了一個很有意義的優(yōu)化:如果要訪問的內(nèi)存區(qū)域(area of memory)在lock前綴指令執(zhí)行期間已經(jīng)在處理器內(nèi)部的緩存中被鎖定(即包含該內(nèi)存區(qū)域的緩存行當前處于獨占或以修改狀態(tài)),并且該內(nèi)存區(qū)域被完全包含在單個緩存行(cache line)中,那么處理器將直接執(zhí)行該指令。由于在指令執(zhí)行期間該緩存行會一直被鎖定,其它處理器無法讀/寫該指令要訪問的內(nèi)存區(qū)域,因此能保證指令執(zhí)行的原子性。這個操作過程叫做緩存鎖定(cache locking)袜爪,緩存鎖定將大大降低lock前綴指令的執(zhí)行開銷昙篙,但是當多處理器之間的競爭程度很高或者指令訪問的內(nèi)存地址未對齊時硕蛹,仍然會鎖住總線埃仪。
禁止該指令與之前和之后的讀和寫指令重排序乙濒。
把寫緩沖區(qū)中的所有數(shù)據(jù)刷新到內(nèi)存中。

備注知識:
關于CPU的鎖有如下3種:
  3.1 處理器自動保證基本內(nèi)存操作的原子性
  首先處理器會自動保證基本的內(nèi)存操作的原子性卵蛉。處理器保證從系統(tǒng)內(nèi)存當中讀取或者寫入一個字節(jié)是原子的颁股,意思是當一個處理器讀取一個字節(jié)時,其他處理器不能訪問這個字節(jié)的內(nèi)存地址傻丝。奔騰6和最新的處理器能自動保證單處理器對同一個緩存行里進行16/32/64位的操作是原子的甘有,但是復雜的內(nèi)存操作處理器不能自動保證其原子性,比如跨總線寬度葡缰,跨多個緩存行亏掀,跨頁表的訪問。但是處理器提供總線鎖定和緩存鎖定兩個機制來保證復雜內(nèi)存操作的原子性泛释。
  3.2 使用總線鎖保證原子性
  第一個機制是通過總線鎖保證原子性滤愕。如果多個處理器同時對共享變量進行讀改寫(i++就是經(jīng)典的讀改寫操作)操作,那么共享變量就會被多個處理器同時進行操作怜校,這樣讀改寫操作就不是原子的间影,操作完之后共享變量的值會和期望的不一致,舉個例子:如果i=1,我們進行兩次i++操作茄茁,我們期望的結(jié)果是3宇智,但是有可能結(jié)果是2蔓搞。如下圖

原因是有可能多個處理器同時從各自的緩存中讀取變量i,分別進行加一操作随橘,然后分別寫入系統(tǒng)內(nèi)存當中。那么想要保證讀改寫共享變量的操作是原子的锦庸,就必須保證CPU1讀改寫共享變量的時候机蔗,CPU2不能操作緩存了該共享變量內(nèi)存地址的緩存。
  處理器使用總線鎖就是來解決這個問題的甘萧。所謂總線鎖就是使用處理器提供的一個LOCK#信號萝嘁,當一個處理器在總線上輸出此信號時,其他處理器的請求將被阻塞住,那么該處理器可以獨占使用共享內(nèi)存扬卷。
  3.3 使用緩存鎖保證原子性
  第二個機制是通過緩存鎖定保證原子性牙言。在同一時刻我們只需保證對某個內(nèi)存地址的操作是原子性即可,但總線鎖定把CPU和內(nèi)存之間通信鎖住了怪得,這使得鎖定期間咱枉,其他處理器不能操作其他內(nèi)存地址的數(shù)據(jù),所以總線鎖定的開銷比較大徒恋,最近的處理器在某些場合下使用緩存鎖定代替總線鎖定來進行優(yōu)化蚕断。
  頻繁使用的內(nèi)存會緩存在處理器的L1,L2和L3高速緩存里入挣,那么原子操作就可以直接在處理器內(nèi)部緩存中進行亿乳,并不需要聲明總線鎖,在奔騰6和最近的處理器中可以使用“緩存鎖定”的方式來實現(xiàn)復雜的原子性径筏。所謂“緩存鎖定”就是如果緩存在處理器緩存行中內(nèi)存區(qū)域在LOCK操作期間被鎖定葛假,當它執(zhí)行鎖操作回寫內(nèi)存時,處理器不在總線上聲言LOCK#信號滋恬,而是修改內(nèi)部的內(nèi)存地址聊训,并允許它的緩存一致性機制來保證操作的原子性,因為緩存一致性機制會阻止同時修改被兩個以上處理器緩存的內(nèi)存區(qū)域數(shù)據(jù)夷恍,當其他處理器回寫已被鎖定的緩存行的數(shù)據(jù)時會起緩存行無效魔眨,在例1中,當CPU1修改緩存行中的i時使用緩存鎖定酿雪,那么CPU2就不能同時緩存了i的緩存行遏暴。
  但是有兩種情況下處理器不會使用緩存鎖定。第一種情況是:當操作的數(shù)據(jù)不能被緩存在處理器內(nèi)部指黎,或操作的數(shù)據(jù)跨多個緩存行(cache line)朋凉,則處理器會調(diào)用總線鎖定。第二種情況是:有些處理器不支持緩存鎖定醋安。對于Inter486和奔騰處理器,就算鎖定的內(nèi)存區(qū)域在處理器的緩存行中也會調(diào)用總線鎖定杂彭。
  以上兩個機制我們可以通過Inter處理器提供了很多LOCK前綴的指令來實現(xiàn)墓毒。比如位測試和修改指令BTS,BTR亲怠,BTC所计,交換指令XADD,CMPXCHG和其他一些操作數(shù)和邏輯指令团秽,比如ADD(加)主胧,OR(或)等,被這些指令操作的內(nèi)存區(qū)域就會加鎖习勤,導致其他處理器不能同時訪問它踪栋。

CAS缺點
CAS雖然很高效的解決原子操作,但是CAS仍然存在三大問題图毕。ABA問題夷都,循環(huán)時間長開銷大和只能保證一個共享變量的原子操作

  1. ABA問題。因為CAS需要在操作值的時候檢查下值有沒有發(fā)生變化予颤,如果沒有發(fā)生變化則更新囤官,但是如果一個值原來是A,變成了B荣瑟,又變成了A治拿,那么使用CAS進行檢查時會發(fā)現(xiàn)它的值沒有發(fā)生變化,但是實際上卻變化了笆焰。ABA問題的解決思路就是使用版本號劫谅。在變量前面追加上版本號,每次變量更新的時候把版本號加一嚷掠,那么A-B-A 就會變成1A-2B-3A捏检。
    從Java1.5開始JDK的atomic包里提供了一個類AtomicStampedReference來解決ABA問題。這個類的compareAndSet方法作用是首先檢查當前引用是否等于預期引用不皆,并且當前標志是否等于預期標志贯城,如果全部相等,則以原子方式將該引用和該標志的值設置為給定的更新值霹娄。
    關于ABA問題參考文檔: http://blog.hesey.net/2011/09/resolve-aba-by-atomicstampedreference.html
    2. 循環(huán)時間長開銷大能犯。自旋CAS如果長時間不成功,會給CPU帶來非常大的執(zhí)行開銷犬耻。如果JVM能支持處理器提供的pause指令那么效率會有一定的提升踩晶,pause指令有兩個作用,第一它可以延遲流水線執(zhí)行指令(de-pipeline),使CPU不會消耗過多的執(zhí)行資源枕磁,延遲的時間取決于具體實現(xiàn)的版本渡蜻,在一些處理器上延遲時間是零。第二它可以避免在退出循環(huán)的時候因內(nèi)存順序沖突(memory order violation)而引起CPU流水線被清空(CPU pipeline flush),從而提高CPU的執(zhí)行效率茸苇。

3. 只能保證一個共享變量的原子操作排苍。當對一個共享變量執(zhí)行操作時,我們可以使用循環(huán)CAS的方式來保證原子操作学密,但是對多個共享變量操作時淘衙,循環(huán)CAS就無法保證操作的原子性,這個時候就可以用鎖腻暮,或者有一個取巧的辦法幔翰,就是把多個共享變量合并成一個共享變量來操作。比如有兩個共享變量i=2,j=a西壮,合并一下ij=2a,然后用CAS來操作ij叫惊。從Java1.5開始JDK提供了AtomicReference類來保證引用對象之間的原子性款青,你可以把多個變量放在一個對象里來進行CAS操作。

concurrent包的實現(xiàn)
由于java的CAS同時具有 volatile 讀和volatile寫的內(nèi)存語義霍狰,因此Java線程之間的通信現(xiàn)在有了下面四種方式:
A線程寫volatile變量抡草,隨后B線程讀這個volatile變量。
A線程寫volatile變量蔗坯,隨后B線程用CAS更新這個volatile變量康震。
A線程用CAS更新一個volatile變量,隨后B線程用CAS更新這個volatile變量宾濒。
A線程用CAS更新一個volatile變量腿短,隨后B線程讀這個volatile變量。

Java的CAS會使用現(xiàn)代處理器上提供的高效機器級別原子指令绘梦,這些原子指令以原子方式對內(nèi)存執(zhí)行讀-改-寫操作橘忱,這是在多處理器中實現(xiàn)同步的關鍵(從本質(zhì)上來說,能夠支持原子性讀-改-寫指令的計算機器卸奉,是順序計算圖靈機的異步等價機器钝诚,因此任何現(xiàn)代的多處理器都會去支持某種能對內(nèi)存執(zhí)行原子性讀-改-寫操作的原子指令)。同時榄棵,volatile變量的讀/寫和CAS可以實現(xiàn)線程之間的通信凝颇。把這些特性整合在一起,就形成了整個concurrent包得以實現(xiàn)的基石疹鳄。如果我們仔細分析concurrent包的源代碼實現(xiàn)拧略,會發(fā)現(xiàn)一個通用化的實現(xiàn)模式:
首先,聲明共享變量為volatile尚辑;
然后辑鲤,使用CAS的原子條件更新來實現(xiàn)線程之間的同步;
同時杠茬,配合以volatile的讀/寫和CAS所具有的volatile讀和寫的內(nèi)存語義來實現(xiàn)線程之間的通信月褥。

Unsafe類

sun.misc.Unsafe

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package sun.misc;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain;
import sun.misc.VM;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;

public final class Unsafe {
    private static final Unsafe theUnsafe;
    public static final int INVALID_FIELD_OFFSET = -1;
    public static final int ARRAY_BOOLEAN_BASE_OFFSET;
    public static final int ARRAY_BYTE_BASE_OFFSET;
    public static final int ARRAY_SHORT_BASE_OFFSET;
    public static final int ARRAY_CHAR_BASE_OFFSET;
    public static final int ARRAY_INT_BASE_OFFSET;
    public static final int ARRAY_LONG_BASE_OFFSET;
    public static final int ARRAY_FLOAT_BASE_OFFSET;
    public static final int ARRAY_DOUBLE_BASE_OFFSET;
    public static final int ARRAY_OBJECT_BASE_OFFSET;
    public static final int ARRAY_BOOLEAN_INDEX_SCALE;
    public static final int ARRAY_BYTE_INDEX_SCALE;
    public static final int ARRAY_SHORT_INDEX_SCALE;
    public static final int ARRAY_CHAR_INDEX_SCALE;
    public static final int ARRAY_INT_INDEX_SCALE;
    public static final int ARRAY_LONG_INDEX_SCALE;
    public static final int ARRAY_FLOAT_INDEX_SCALE;
    public static final int ARRAY_DOUBLE_INDEX_SCALE;
    public static final int ARRAY_OBJECT_INDEX_SCALE;
    public static final int ADDRESS_SIZE;

    private static native void registerNatives();

    private Unsafe() {
    }

    @CallerSensitive
    public static Unsafe getUnsafe() {
        Class var0 = Reflection.getCallerClass();
        if(!VM.isSystemDomainLoader(var0.getClassLoader())) {
            throw new SecurityException("Unsafe");
        } else {
            return theUnsafe;
        }
    }

    public native int getInt(Object var1, long var2);

    public native void putInt(Object var1, long var2, int var4);

    public native Object getObject(Object var1, long var2);

    public native void putObject(Object var1, long var2, Object var4);

    public native boolean getBoolean(Object var1, long var2);

    public native void putBoolean(Object var1, long var2, boolean var4);

    public native byte getByte(Object var1, long var2);

    public native void putByte(Object var1, long var2, byte var4);

    public native short getShort(Object var1, long var2);

    public native void putShort(Object var1, long var2, short var4);

    public native char getChar(Object var1, long var2);

    public native void putChar(Object var1, long var2, char var4);

    public native long getLong(Object var1, long var2);

    public native void putLong(Object var1, long var2, long var4);

    public native float getFloat(Object var1, long var2);

    public native void putFloat(Object var1, long var2, float var4);

    public native double getDouble(Object var1, long var2);

    public native void putDouble(Object var1, long var2, double var4);

    /** @deprecated */
    @Deprecated
    public int getInt(Object var1, int var2) {
        return this.getInt(var1, (long)var2);
    }

    /** @deprecated */
    @Deprecated
    public void putInt(Object var1, int var2, int var3) {
        this.putInt(var1, (long)var2, var3);
    }

    /** @deprecated */
    @Deprecated
    public Object getObject(Object var1, int var2) {
        return this.getObject(var1, (long)var2);
    }

    /** @deprecated */
    @Deprecated
    public void putObject(Object var1, int var2, Object var3) {
        this.putObject(var1, (long)var2, var3);
    }

    /** @deprecated */
    @Deprecated
    public boolean getBoolean(Object var1, int var2) {
        return this.getBoolean(var1, (long)var2);
    }

    /** @deprecated */
    @Deprecated
    public void putBoolean(Object var1, int var2, boolean var3) {
        this.putBoolean(var1, (long)var2, var3);
    }

    /** @deprecated */
    @Deprecated
    public byte getByte(Object var1, int var2) {
        return this.getByte(var1, (long)var2);
    }

    /** @deprecated */
    @Deprecated
    public void putByte(Object var1, int var2, byte var3) {
        this.putByte(var1, (long)var2, var3);
    }

    /** @deprecated */
    @Deprecated
    public short getShort(Object var1, int var2) {
        return this.getShort(var1, (long)var2);
    }

    /** @deprecated */
    @Deprecated
    public void putShort(Object var1, int var2, short var3) {
        this.putShort(var1, (long)var2, var3);
    }

    /** @deprecated */
    @Deprecated
    public char getChar(Object var1, int var2) {
        return this.getChar(var1, (long)var2);
    }

    /** @deprecated */
    @Deprecated
    public void putChar(Object var1, int var2, char var3) {
        this.putChar(var1, (long)var2, var3);
    }

    /** @deprecated */
    @Deprecated
    public long getLong(Object var1, int var2) {
        return this.getLong(var1, (long)var2);
    }

    /** @deprecated */
    @Deprecated
    public void putLong(Object var1, int var2, long var3) {
        this.putLong(var1, (long)var2, var3);
    }

    /** @deprecated */
    @Deprecated
    public float getFloat(Object var1, int var2) {
        return this.getFloat(var1, (long)var2);
    }

    /** @deprecated */
    @Deprecated
    public void putFloat(Object var1, int var2, float var3) {
        this.putFloat(var1, (long)var2, var3);
    }

    /** @deprecated */
    @Deprecated
    public double getDouble(Object var1, int var2) {
        return this.getDouble(var1, (long)var2);
    }

    /** @deprecated */
    @Deprecated
    public void putDouble(Object var1, int var2, double var3) {
        this.putDouble(var1, (long)var2, var3);
    }

    public native byte getByte(long var1);

    public native void putByte(long var1, byte var3);

    public native short getShort(long var1);

    public native void putShort(long var1, short var3);

    public native char getChar(long var1);

    public native void putChar(long var1, char var3);

    public native int getInt(long var1);

    public native void putInt(long var1, int var3);

    public native long getLong(long var1);

    public native void putLong(long var1, long var3);

    public native float getFloat(long var1);

    public native void putFloat(long var1, float var3);

    public native double getDouble(long var1);

    public native void putDouble(long var1, double var3);

    public native long getAddress(long var1);

    public native void putAddress(long var1, long var3);

    public native long allocateMemory(long var1);

    public native long reallocateMemory(long var1, long var3);

    public native void setMemory(Object var1, long var2, long var4, byte var6);

    public void setMemory(long var1, long var3, byte var5) {
        this.setMemory((Object)null, var1, var3, var5);
    }

    public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7);

    public void copyMemory(long var1, long var3, long var5) {
        this.copyMemory((Object)null, var1, (Object)null, var3, var5);
    }

    public native void freeMemory(long var1);

    /** @deprecated */
    @Deprecated
    public int fieldOffset(Field var1) {
        return Modifier.isStatic(var1.getModifiers())?(int)this.staticFieldOffset(var1):(int)this.objectFieldOffset(var1);
    }

    /** @deprecated */
    @Deprecated
    public Object staticFieldBase(Class<?> var1) {
        Field[] var2 = var1.getDeclaredFields();

        for(int var3 = 0; var3 < var2.length; ++var3) {
            if(Modifier.isStatic(var2[var3].getModifiers())) {
                return this.staticFieldBase(var2[var3]);
            }
        }

        return null;
    }

    public native long staticFieldOffset(Field var1);

    public native long objectFieldOffset(Field var1);

    public native Object staticFieldBase(Field var1);

    public native boolean shouldBeInitialized(Class<?> var1);

    public native void ensureClassInitialized(Class<?> var1);

    public native int arrayBaseOffset(Class<?> var1);

    public native int arrayIndexScale(Class<?> var1);

    public native int addressSize();

    public native int pageSize();

    public native Class<?> defineClass(String var1, byte[] var2, int var3, int var4, ClassLoader var5, ProtectionDomain var6);

    public native Class<?> defineAnonymousClass(Class<?> var1, byte[] var2, Object[] var3);

    public native Object allocateInstance(Class<?> var1) throws InstantiationException;

    public native void monitorEnter(Object var1);

    public native void monitorExit(Object var1);

    public native boolean tryMonitorEnter(Object var1);

    public native void throwException(Throwable var1);

    public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);

    public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

    public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

    public native Object getObjectVolatile(Object var1, long var2);

    public native void putObjectVolatile(Object var1, long var2, Object var4);

    public native int getIntVolatile(Object var1, long var2);

    public native void putIntVolatile(Object var1, long var2, int var4);

    public native boolean getBooleanVolatile(Object var1, long var2);

    public native void putBooleanVolatile(Object var1, long var2, boolean var4);

    public native byte getByteVolatile(Object var1, long var2);

    public native void putByteVolatile(Object var1, long var2, byte var4);

    public native short getShortVolatile(Object var1, long var2);

    public native void putShortVolatile(Object var1, long var2, short var4);

    public native char getCharVolatile(Object var1, long var2);

    public native void putCharVolatile(Object var1, long var2, char var4);

    public native long getLongVolatile(Object var1, long var2);

    public native void putLongVolatile(Object var1, long var2, long var4);

    public native float getFloatVolatile(Object var1, long var2);

    public native void putFloatVolatile(Object var1, long var2, float var4);

    public native double getDoubleVolatile(Object var1, long var2);

    public native void putDoubleVolatile(Object var1, long var2, double var4);

    public native void putOrderedObject(Object var1, long var2, Object var4);

    public native void putOrderedInt(Object var1, long var2, int var4);

    public native void putOrderedLong(Object var1, long var2, long var4);

    public native void unpark(Object var1);

    public native void park(boolean var1, long var2);

    public native int getLoadAverage(double[] var1, int var2);

    public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

    public final long getAndAddLong(Object var1, long var2, long var4) {
        long var6;
        do {
            var6 = this.getLongVolatile(var1, var2);
        } while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));

        return var6;
    }

    public final int getAndSetInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var4));

        return var5;
    }

    public final long getAndSetLong(Object var1, long var2, long var4) {
        long var6;
        do {
            var6 = this.getLongVolatile(var1, var2);
        } while(!this.compareAndSwapLong(var1, var2, var6, var4));

        return var6;
    }

    public final Object getAndSetObject(Object var1, long var2, Object var4) {
        Object var5;
        do {
            var5 = this.getObjectVolatile(var1, var2);
        } while(!this.compareAndSwapObject(var1, var2, var5, var4));

        return var5;
    }

    public native void loadFence();

    public native void storeFence();

    public native void fullFence();

    private static void throwIllegalAccessError() {
        throw new IllegalAccessError();
    }

    static {
        registerNatives();
        Reflection.registerMethodsToFilter(Unsafe.class, new String[]{"getUnsafe"});
        theUnsafe = new Unsafe();
        ARRAY_BOOLEAN_BASE_OFFSET = theUnsafe.arrayBaseOffset(boolean[].class);
        ARRAY_BYTE_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class);
        ARRAY_SHORT_BASE_OFFSET = theUnsafe.arrayBaseOffset(short[].class);
        ARRAY_CHAR_BASE_OFFSET = theUnsafe.arrayBaseOffset(char[].class);
        ARRAY_INT_BASE_OFFSET = theUnsafe.arrayBaseOffset(int[].class);
        ARRAY_LONG_BASE_OFFSET = theUnsafe.arrayBaseOffset(long[].class);
        ARRAY_FLOAT_BASE_OFFSET = theUnsafe.arrayBaseOffset(float[].class);
        ARRAY_DOUBLE_BASE_OFFSET = theUnsafe.arrayBaseOffset(double[].class);
        ARRAY_OBJECT_BASE_OFFSET = theUnsafe.arrayBaseOffset(Object[].class);
        ARRAY_BOOLEAN_INDEX_SCALE = theUnsafe.arrayIndexScale(boolean[].class);
        ARRAY_BYTE_INDEX_SCALE = theUnsafe.arrayIndexScale(byte[].class);
        ARRAY_SHORT_INDEX_SCALE = theUnsafe.arrayIndexScale(short[].class);
        ARRAY_CHAR_INDEX_SCALE = theUnsafe.arrayIndexScale(char[].class);
        ARRAY_INT_INDEX_SCALE = theUnsafe.arrayIndexScale(int[].class);
        ARRAY_LONG_INDEX_SCALE = theUnsafe.arrayIndexScale(long[].class);
        ARRAY_FLOAT_INDEX_SCALE = theUnsafe.arrayIndexScale(float[].class);
        ARRAY_DOUBLE_INDEX_SCALE = theUnsafe.arrayIndexScale(double[].class);
        ARRAY_OBJECT_INDEX_SCALE = theUnsafe.arrayIndexScale(Object[].class);
        ADDRESS_SIZE = theUnsafe.addressSize();
    }
}

參考文檔:
http://www.blogjava.NET/xylz/archive/2010/07/04/325206.html
http://blog.hesey.Net/2011/09/resolve-aba-by-atomicstampedreference.html
http://www.searchsoa.com.cn/showcontent_69238.htm
http://ifeve.com/atomic-operation/
http://www.infoq.com/cn/articles/Java-memory-model-5

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末弛随,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子宁赤,更是在濱河造成了極大的恐慌舀透,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件决左,死亡現(xiàn)場離奇詭異愕够,居然都是意外死亡,警方通過查閱死者的電腦和手機佛猛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門惑芭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人继找,你說我怎么就攤上這事遂跟。” “怎么了婴渡?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵幻锁,是天一觀的道長。 經(jīng)常有香客問我边臼,道長哄尔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任柠并,我火速辦了婚禮岭接,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘堂鲤。我一直安慰自己亿傅,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布瘟栖。 她就那樣靜靜地躺著葵擎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪半哟。 梳的紋絲不亂的頭發(fā)上酬滤,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音寓涨,去河邊找鬼盯串。 笑死,一個胖子當著我的面吹牛戒良,可吹牛的內(nèi)容都是我干的体捏。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼几缭!你這毒婦竟也來了河泳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤年栓,失蹤者是張志新(化名)和其女友劉穎拆挥,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體某抓,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡纸兔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了否副。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汉矿。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖备禀,靈堂內(nèi)的尸體忽然破棺而出负甸,到底是詐尸還是另有隱情,我是刑警寧澤痹届,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站打月,受9級特大地震影響队腐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜奏篙,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一柴淘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧秘通,春花似錦为严、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至话原,卻和暖如春夕吻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背繁仁。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工涉馅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人黄虱。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓稚矿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親疆虚。 傳聞我的和親對象是個殘疾皇子案淋,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容

  • CAS原理深度分析 java.util.concurrent包完全建立在CAS之上的裁眯,沒有CAS就不會有此包斗埂÷拢可見...
    史路比閱讀 481評論 0 5
  • 引用地址 java.util.concurrent包完全建立在CAS之上的焰扳,沒有CAS就不會有此包辆琅〔馍埃可見CAS的重...
    Lisy_閱讀 721評論 0 14
  • 在分析說明 volatile 和 CAS 的實現(xiàn)原理前,我們需要先了解一些預備知識习霹,這將是對 volatile 和...
    tomas家的小撥浪鼓閱讀 12,136評論 14 44
  • 第2章 java并發(fā)機制的底層實現(xiàn)原理 Java中所使用的并發(fā)機制依賴于JVM的實現(xiàn)和CPU的指令朵耕。 2.1 vo...
    kennethan閱讀 1,392評論 0 2
  • 談寫都會寫,一作可就變難了淋叶。寫字阎曹、寫說、寫文章煞檩,這是從開始識字起处嫌,由一個個漢字寫起,每天一個漢字寫二行斟湃,后來...
    x123閱讀 266評論 0 0