Java 底層CAS原理 & Concurrent包實(shí)現(xiàn)

CAS:

Compare and Swap, 翻譯成比較并交換。
java.util.concurrent包中借助CAS實(shí)現(xiàn)了區(qū)別于synchronouse同步鎖的一種樂(lè)觀鎖。

CAS實(shí)現(xiàn)原理:

CAS有3個(gè)操作數(shù),內(nèi)存值V,舊的預(yù)期值A(chǔ),要修改的新值B。當(dāng)且僅當(dāng)預(yù)期值A(chǔ)和內(nèi)存值V相同時(shí),將內(nèi)存值V修改為B,否則什么都不做。

boolean compareAndSwap( V, A, B){
    if (V != A) {
        return false;
    } else {
        V = B;
        return true;
    }
}

這個(gè)過(guò)程在硬件層面實(shí)現(xiàn)的,Java主要用JNI類 UNSAFE實(shí)現(xiàn)的。
這里不詳細(xì)描述其具實(shí)現(xiàn),詳情:UNSAFE詳情

CAS 缺點(diǎn):

  1. ABA問(wèn)題:就是當(dāng)修改,從A改成B,再?gòu)腂改回A。那么CAS算法會(huì)當(dāng)他沒(méi)有變化,但實(shí)際上數(shù)據(jù)是變化了。
    解決方法: 加入版本控制,每次操作都有版本號(hào)。
    處理過(guò)程: 先檢查值有沒(méi)變化,如果沒(méi)變,再檢查版本號(hào)。

  2. 循環(huán)時(shí)間過(guò)長(zhǎng):CAS如果長(zhǎng)時(shí)間不成功,就會(huì)浪費(fèi)掉非常多的CPU資源。
    解決方法:pause指令。有兩個(gè)作用:
    a. 可以延遲流水線執(zhí)行指令(de-pipeline),使CPU不會(huì)消耗過(guò)多的執(zhí)行資源,延遲的時(shí)間取決于具體實(shí)現(xiàn)的版本,在一些處理器上延遲時(shí)間是零。
    b. 可以避免在退出循環(huán)的時(shí)候因內(nèi)存順序沖突(memory order violation)而引起CPU流水線被清空(CPU pipeline flush),從而提高CPU的執(zhí)行效率。

  3. 只能保證一個(gè)共享變量的原子操作:當(dāng)操作一個(gè)共享變量時(shí),可以使用CAS,但一個(gè)原子操作有多個(gè)共享變量時(shí)。我們只能用鎖來(lái)解決問(wèn)題,獲取把多個(gè)共享變量合并成一個(gè)共享變量。
    解決方法:
    a. 使用鎖控制幾個(gè)共享變量;
    b. 合并幾個(gè)共享變量使用CAS。


concurrent包的實(shí)現(xiàn)

由于java的CAS同時(shí)具有 volatile 讀和volatile寫(xiě)的內(nèi)存語(yǔ)義,因此Java線程之間的通信現(xiàn)在有了下面四種方式:

  1. A線程寫(xiě)volatile變量,隨后B線程讀這個(gè)volatile變量。
  2. A線程寫(xiě)volatile變量,隨后B線程用CAS更新這個(gè)volatile變量。
  3. A線程用CAS更新一個(gè)volatile變量,隨后B線程用CAS更新這個(gè)volatile變量。
  4. A線程用CAS更新一個(gè)volatile變量,隨后B線程讀這個(gè)volatile變量。

Java的CAS會(huì)使用現(xiàn)代處理器上提供的高效機(jī)器級(jí)別原子指令,這些原子指令以原子方式對(duì)內(nèi)存執(zhí)行讀-改-寫(xiě)操作,這是在多處理器中實(shí)現(xiàn)同步的關(guān)鍵(從本質(zhì)上來(lái)說(shuō),能夠支持原子性讀-改-寫(xiě)指令的計(jì)算機(jī)器,是順序計(jì)算圖靈機(jī)的異步等價(jià)機(jī)器,因此任何現(xiàn)代的多處理器都會(huì)去支持某種能對(duì)內(nèi)存執(zhí)行原子性讀-改-寫(xiě)操作的原子指令)。同時(shí),volatile變量的讀/寫(xiě)和CAS可以實(shí)現(xiàn)線程之間的通信。把這些特性整合在一起,就形成了整個(gè)concurrent包得以實(shí)現(xiàn)的基石。如果我們仔細(xì)分析concurrent包的源代碼實(shí)現(xiàn),會(huì)發(fā)現(xiàn)一個(gè)通用化的實(shí)現(xiàn)模式:

  1. 首先,聲明共享變量為volatile;
  2. 然后,使用CAS的原子條件更新來(lái)實(shí)現(xiàn)線程之間的同步;
  3. 同時(shí),配合以volatile的讀/寫(xiě)和CAS所具有的volatile讀和寫(xiě)的內(nèi)存語(yǔ)義來(lái)實(shí)現(xiàn)線程之間的通信。

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


concurrent結(jié)構(gòu)

參考文檔:
http://www.cnblogs.com/zhuawang/p/4196904.html
concurrent包的實(shí)現(xiàn)內(nèi)容完全轉(zhuǎn)載
http://www.cnblogs.com/zhuawang/p/4196904.html

?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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