Java CAS機(jī)制

Conmpare And Swap(比較并且交換),樂觀鎖的一種實(shí)現(xiàn)方式

1.5引入CAS即Java原子類
java.util.concurrent.atomic
jdk所提供的原子類可以大致分為四種類型:

  • 原子更新基本數(shù)據(jù)類型,AtomicLong,AtomicInteger,AtomicBoolean
  • 原子更新數(shù)組類型,AtomicLongArray,AtomicIntegerArray
  • 原子更新對(duì)象引用,AtomicReference
  • 原子更新字段(基于反射),AtomicIntegerFieldUpdater

以AtomicInteger的compareAndSet為例
/CAS操作有三個(gè)操作數(shù):內(nèi)存值,預(yù)期值,更新值/

public final boolean compareAndSet(int expect, int update) {
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
//valueOffset是value在內(nèi)存中的偏移量
private static final long valueOffset;
private volatile int value;

Unsafe是Java中一個(gè)底層類,包含了很多基礎(chǔ)的操作,比如數(shù)組操作、對(duì)象操作、內(nèi)存操作、CAS操作、線程(park)操作、柵欄(Fence)操作,JUC包、一些三方框架都使用Unsafe類來保證并發(fā)安全。

Unsafe里的native方法參考

特點(diǎn):1.循環(huán)(自旋)開銷大;2.只能保證一個(gè)變量的原子性操作
3.ABA問題
指在CAS操作時(shí),其他線程將變量值A(chǔ)改為了B,但是又被改回了A,等到本線程使用期望值A(chǔ)與當(dāng)前變量進(jìn)行比較時(shí),發(fā)現(xiàn)變量A沒有變,于是CAS就將A值進(jìn)行了交換操作,但是實(shí)際上該值已經(jīng)被其他線程改變過,這與樂觀鎖的設(shè)計(jì)思想不符合。

一般的解決思路:添加版本號(hào),每次變量更新的時(shí)候把變量的版本號(hào)加1,那么A-B-A就會(huì)變成A1-B2-A3,只要變量被某一線程修改過,改變量對(duì)應(yīng)的版本號(hào)就會(huì)發(fā)生遞增變化,從而解決了ABA問題。

JDK的解決方法:在java.util.concurrent.atomic包中提供了AtomicStampedReference和AtomicMarkableReference

public class AtomicStampedReference<V> {
    //省略源碼其余部分
    /* 構(gòu)造函數(shù)
     * @param initialRef the initial reference 初始引用
     * @param initialStamp the initial stamp 相當(dāng)于初始版本號(hào)
     */
    public AtomicStampedReference(V initialRef, int initialStamp) {
        pair = Pair.of(initialRef, initialStamp);
    }
    /*核心*/
    public boolean compareAndSet(V   expectedReference,
                                 V   newReference,
                                 int expectedStamp,
                                 int newStamp) {
        Pair<V> current = pair;
        return
            //當(dāng)reference和stamp都相等時(shí),才允許CAS操作
            expectedReference == current.reference &&
            expectedStamp == current.stamp &&
            ((newReference == current.reference &&
              newStamp == current.stamp) ||
             casPair(current, Pair.of(newReference, newStamp)));
    }
}

AtomicMarkableReference是AtomicStampedReference的簡(jiǎn)化版,不關(guān)心修改過幾次,僅僅關(guān)心是否修改過。因此變量mark是boolean類型,僅記錄值是否有過修改。

    public AtomicMarkableReference(V initialRef, boolean initialMark) { pair = Pair.of(initialRef, initialMark);}

    public boolean compareAndSet(V       expectedReference,
                                 V       newReference,
                                 boolean expectedMark,
                                 boolean newMark) {
        Pair<V> current = pair;
        return
            expectedReference == current.reference &&
            expectedMark == current.mark &&
            ((newReference == current.reference &&
              newMark == current.mark) ||
             casPair(current, Pair.of(newReference, newMark)));
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容