多線程-CAS

一、什么是CAS?

CAS,全稱Compare And Swap(比較與交換),解決多線程并行情況下使用鎖造成性能損耗的一種機(jī)制。
CAS 操作包含三個(gè)操作數(shù) —— 內(nèi)存位置(V)、預(yù)期原值(A)和新值(B)。 如果內(nèi)存位置的值與預(yù)期原值相匹配,那么處理器會自動將該位置值更新為新值 。否則,處理器不做任何操作。無論哪種情況,它都會在 CAS 指令之前返回該 位置的值

二、CAS的目的

利用CPU的CAS指令,同時(shí)借助JNI來完成Java的非阻塞算法。其它原子操作都是利用類似的特性完成的。而整個(gè)J.U.C都是建立在CAS之上的,因此對于synchronized阻塞算法,J.U.C在性能上有了很大的提升。

三、CAS(compareAndSwap)的原理探究

CAS的實(shí)現(xiàn)主要在JUC中的atomic包,我們以AtomicInteger類為例:

  /**
     * Atomically increments by one the current value.
     *
     * @return the updated value
     */
    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }

通過代碼追溯,可以看出JAVA中的CAS操作都是通過sun包下Unsafe類實(shí)現(xiàn),而Unsafe類中的方法都是native方法,由JVM本地實(shí)現(xiàn),所以最終的實(shí)現(xiàn)是基于C、C++在操作系統(tǒng)之上操作

Unsafe類

java不能直接訪問操作系統(tǒng)底層,而是通過本地方法來訪問。Unsafe類提供了硬件級別的原子操作,主要提供了以下功能:
1、通過Unsafe類可以分配內(nèi)存,可以釋放內(nèi)存;
類中提供的3個(gè)本地方法allocateMemory、reallocateMemory、freeMemory分別用于分配內(nèi)存,擴(kuò)充內(nèi)存和釋放內(nèi)存,與C語言中的3個(gè)方法對應(yīng)。
2、可以定位對象某字段的內(nèi)存位置,也可以修改對象的字段值,即使它是私有的;
3、掛起與恢復(fù)
將一個(gè)線程進(jìn)行掛起是通過park方法實(shí)現(xiàn)的,調(diào)用 park后,線程將一直阻塞直到超時(shí)或者中斷等條件出現(xiàn)。unpark可以終止一個(gè)掛起的線程,使其恢復(fù)正常。整個(gè)并發(fā)框架中對線程的掛起操作被封裝在 LockSupport類中,LockSupport類中有各種版本pack方法,但最終都調(diào)用了Unsafe.park()方法。

public class LockSupport {
    public static void unpark(Thread thread) {
        if (thread != null)
            unsafe.unpark(thread);
    }

    public static void park(Object blocker) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        unsafe.park(false, 0L);
        setBlocker(t, null);
    }

    public static void parkNanos(Object blocker, long nanos) {
        if (nanos > 0) {
            Thread t = Thread.currentThread();
            setBlocker(t, blocker);
            unsafe.park(false, nanos);
            setBlocker(t, null);
        }
    }

    public static void parkUntil(Object blocker, long deadline) {
        Thread t = Thread.currentThread();
        setBlocker(t, blocker);
        unsafe.park(true, deadline);
        setBlocker(t, null);
    }

    public static void park() {
        unsafe.park(false, 0L);
    }

    public static void parkNanos(long nanos) {
        if (nanos > 0)
            unsafe.park(false, nanos);
    }

    public static void parkUntil(long deadline) {
        unsafe.park(true, deadline);
    }
}

4、CAS操作

/**
     * Atomically update Java variable to <tt>x</tt> if it is currently
     * holding <tt>expected</tt>.
     * @return <tt>true</tt> if successful
     */
    public final native boolean compareAndSwapObject(Object o, long offset,
                                                     Object expected,
                                                     Object x);

    /**
     * Atomically update Java variable to <tt>x</tt> if it is currently
     * holding <tt>expected</tt>.
     * @return <tt>true</tt> if successful
     */
    public final native boolean compareAndSwapInt(Object o, long offset,
                                                  int expected,
                                                  int x);

    /**
     * Atomically update Java variable to <tt>x</tt> if it is currently
     * holding <tt>expected</tt>.
     * @return <tt>true</tt> if successful
     */
    public final native boolean compareAndSwapLong(Object o, long offset,
                                                   long expected,
                                                   long x);

四、CAS機(jī)制的優(yōu)缺點(diǎn)

4.1 優(yōu)點(diǎn)
CAS是一種樂觀鎖,而且是一種非阻塞的輕量級的樂觀鎖,什么是非阻塞式的呢?其實(shí)就是一個(gè)線程想要獲得鎖,對方會給一個(gè)回應(yīng)表示這個(gè)鎖能不能獲得。在資源競爭不激烈的情況下性能高,相比synchronized重量鎖,synchronized會進(jìn)行比較復(fù)雜的加鎖,解鎖和喚醒操作。

4.2 缺點(diǎn)
1)循環(huán)時(shí)間長開銷大,占用CPU資源

2)只能保證一個(gè)共享變量的原子操作

3)ABA問題
如線程1從內(nèi)存X中取出A,這時(shí)候另一個(gè)線程2也從內(nèi)存X中取出A,并且線程2進(jìn)行了一些操作將內(nèi)存X中的值變成了B,然后線程2又將內(nèi)存X中的數(shù)據(jù)變成A,這時(shí)候線程1進(jìn)行CAS操作發(fā)現(xiàn)內(nèi)存X中仍然是A,然后線程1操作成功。雖然線程1的CAS操作成功,但是整個(gè)過程就是有問題的。比如鏈表的頭在變化了兩次后恢復(fù)了原值,但是不代表鏈表就沒有變化。

ABA問題解決方案:
1、添加版本號
2、AtomicStampedReference
java并發(fā)包為了解決這個(gè)問題,提供了一個(gè)帶有標(biāo)記的原子引用類“AtomicStampedReference”,它可以通過控制變量值的版本來保證CAS的正確性。因此,在使用CAS前要考慮清楚“ABA”問題是否會影響程序并發(fā)的正確性,如果需要解決ABA問題,改用傳統(tǒng)的互斥同步可能會比原子類更高效。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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