真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

java中CAS是什么

這篇文章給大家分享的是有關(guān)java中CAS是什么的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來看看吧。

10年的東湖網(wǎng)站建設(shè)經(jīng)驗(yàn),針對設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。網(wǎng)絡(luò)營銷推廣的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動調(diào)整東湖建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。成都創(chuàng)新互聯(lián)公司從事“東湖網(wǎng)站設(shè)計(jì)”,“東湖網(wǎng)站推廣”以來,每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。

前言

Java并發(fā)編程系列番外篇C A S(Compare and swap),文章風(fēng)格依然是圖文并茂,通俗易懂,讓讀者們也能與面試官瘋狂對線。

C A S作為并發(fā)編程必不可少的基礎(chǔ)知識,面試時(shí)C A S也是個(gè)高頻考點(diǎn),所以說C A S是必知必會,本文將帶讀者們深入理解C A S。

大綱

java中CAS是什么

C A S基本概念

C A S(compareAndSwap)也叫比較交換,是一種無鎖原子算法,映射到操作系統(tǒng)就是一條cmpxchg硬件匯編指令(保證原子性),其作用是讓C P U將內(nèi)存值更新為新值,但是有個(gè)條件,內(nèi)存值必須與期望值相同,并且C A S操作無需用戶態(tài)與內(nèi)核態(tài)切換,直接在用戶態(tài)對內(nèi)存進(jìn)行讀寫操作(意味著不會阻塞/線程上下文切換)。

它包含3個(gè)參數(shù)C A S(V,E,N)V表示待更新的內(nèi)存值,E表示預(yù)期值,N表示新值,當(dāng) V值等于E值時(shí),才會將V值更新成N值,如果V值和E值不等,不做更新,這就是一次C A S的操作。

java中CAS是什么

簡單說,C A S需要你額外給出一個(gè)期望值,也就是你認(rèn)為這個(gè)變量現(xiàn)在應(yīng)該是什么樣子的,如果變量不是你想象的那樣,說明它已經(jīng)被別人修改過了,你只需要重新讀取,設(shè)置新期望值,再次嘗試修改就好了。

C A S如何保證原子性

原子性是指一個(gè)或者多個(gè)操作在C P U執(zhí)行的過程中不被中斷的特性,要么執(zhí)行,要不執(zhí)行,不能執(zhí)行到一半(不可被中斷的一個(gè)或一系列操作)。

為了保證C A S的原子性,C P U提供了下面兩種方式

  • 總線鎖定

  • 緩存鎖定

總線鎖定

總線(B U S)是計(jì)算機(jī)組件間的傳輸數(shù)據(jù)方式,也就是說C P U與其他組件連接傳輸數(shù)據(jù),就是靠總線完成的,比如C P U對內(nèi)存的讀寫。

java中CAS是什么

總線鎖定是指C P U使用了總線鎖,所謂總線鎖就是使用C P U提供的LOCK#信號,當(dāng)C P U在總線上輸出LOCK#信號時(shí),其他C P U的總線請求將被阻塞。

java中CAS是什么

緩存鎖定

總線鎖定方式雖然保證了原子性,但是在鎖定期間,會導(dǎo)致大量阻塞,增加系統(tǒng)的性能開銷,所以現(xiàn)代C P U為了提升性能,通過鎖定范圍縮小的思想設(shè)計(jì)出了緩存行鎖定(緩存行是C P U高速緩存存儲的最小單位)。

所謂緩存鎖定是指C P U緩存行進(jìn)行鎖定,當(dāng)緩存行中的共享變量回寫到內(nèi)存時(shí),其他C P U會通過總線嗅探機(jī)制感知該共享變量是否發(fā)生變化,如果發(fā)生變化,讓自己對應(yīng)的共享變量緩存行失效,重新從內(nèi)存讀取最新的數(shù)據(jù),緩存鎖定是基于緩存一致性機(jī)制來實(shí)現(xiàn)的,因?yàn)榫彺嬉恢滦詸C(jī)制會阻止兩個(gè)以上C P U同時(shí)修改同一個(gè)共享變量(現(xiàn)代C P U基本都支持和使用緩存鎖定機(jī)制)。

C A S的問題

C A S和鎖都解決了原子性問題,和鎖相比沒有阻塞、線程上下文你切換、死鎖,所以C A S要比鎖擁有更優(yōu)越的性能,但是C A S同樣存在缺點(diǎn)。

C A S的問題如下

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

  • 自旋時(shí)間太長(建立在自旋鎖的基礎(chǔ)上)

  • ABA問題

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

C A S只能針對一個(gè)共享變量使用,如果多個(gè)共享變量就只能使用鎖了,當(dāng)然如果你有辦法把多個(gè)變量整成一個(gè)變量,利用C A S也不錯,例如讀寫鎖中state的高低位。

自旋時(shí)間太長

當(dāng)一個(gè)線程獲取鎖時(shí)失敗,不進(jìn)行阻塞掛起,而是間隔一段時(shí)間再次嘗試獲取,直到成功為止,這種循環(huán)獲取的機(jī)制被稱為自旋鎖(spinlock)。

自旋鎖好處是,持有鎖的線程在短時(shí)間內(nèi)釋放鎖,那些等待競爭鎖的線程就不需進(jìn)入阻塞狀態(tài)(無需線程上下文切換/無需用戶態(tài)與內(nèi)核態(tài)切換),它們只需要等一等(自旋),等到持有鎖的線程釋放鎖之后即可獲取,這樣就避免了用戶態(tài)和內(nèi)核態(tài)的切換消耗。

自旋鎖壞處顯而易見,線程在長時(shí)間內(nèi)持有鎖,等待競爭鎖的線程一直自旋,即CPU一直空轉(zhuǎn),資源浪費(fèi)在毫無意義的地方,所以一般會限制自旋次數(shù)。

最后來說自旋鎖的實(shí)現(xiàn),實(shí)現(xiàn)自旋鎖可以基于C A S實(shí)現(xiàn),先定義lockValue對象默認(rèn)值1,1代表鎖資源空閑,0代表鎖資源被占用,代碼如下

public class SpinLock {
    
    //lockValue 默認(rèn)值1
    private AtomicInteger lockValue = new AtomicInteger(1);
    
    //自旋獲取鎖
    public void lock(){

        // 循環(huán)檢測嘗試獲取鎖
        while (!tryLock()){
            // 空轉(zhuǎn)
        }

    }
    
    //獲取鎖
    public boolean tryLock(){
        // 期望值1,更新值0,更新成功返回true,更新失敗返回false
        return lockValue.compareAndSet(1,0);
    }
    
    //釋放鎖
    public void unLock(){
        if(!lockValue.compareAndSet(1,0)){
            throw new RuntimeException("釋放鎖失敗");
        }
    }

}

上面定義了AtomicInteger類型的lockValue變量,AtomicIntegerJava基于C A S實(shí)現(xiàn)的Integer原子操作類,還定義了3個(gè)函數(shù)lock、tryLock、unLock

tryLock函數(shù)-獲取鎖

  • 期望值1,更新值0

  • C A S更新

  • 如果期望值與lockValue值相等,則lockValue值更新為0,返回true,否則執(zhí)行下面邏輯

  • 如果期望值與lockValue值不相等,不做任何更新,返回false

unLock函數(shù)-釋放鎖

  • 期望值0,更新值1

  • C A S更新

  • 如果期望值與lockValue值相等,則lockValue值更新為1,返回true,否則執(zhí)行下面邏輯

  • 如果期望值與lockValue值不相等,不做任何更新,返回false

lock函數(shù)-自旋獲取鎖

  • 執(zhí)行tryLock函數(shù),返回true停止,否則一直循環(huán)

java中CAS是什么

從上圖可以看出,只有tryLock成功的線程(lockValue更新為0),才會執(zhí)行代碼塊,其他線程個(gè)tryLock自旋等待lockValue被更新成1tryLock成功的線程執(zhí)行unLocklockValue更新為1),自旋的線程才會tryLock成功。

ABA問題

C A S需要檢查待更新的內(nèi)存值有沒有被修改,如果沒有則更新,但是存在這樣一種情況,如果一個(gè)值原來是A,變成了B,然后又變成了A,在C A S檢查的時(shí)候會發(fā)現(xiàn)沒有被修改。

假設(shè)有兩個(gè)線程,線程1讀取到內(nèi)存值A,線程1時(shí)間片用完,切換到線程2,線程2也讀取到了內(nèi)存值A,并把它修改為B值,然后再把B值還原到A值,簡單說,修改次序是A->B->A,接著線程1恢復(fù)運(yùn)行,它發(fā)現(xiàn)內(nèi)存值還是A,然后執(zhí)行C A S操作,這就是著名的ABA問題,但是好像又看不出什么問題。

只是簡單的數(shù)據(jù)結(jié)構(gòu),確實(shí)不會有什么問題,如果是復(fù)雜的數(shù)據(jù)結(jié)構(gòu)可能就會有問題了(使用AtomicReference可以把C A S使用在對象上),以鏈表數(shù)據(jù)結(jié)構(gòu)為例,兩個(gè)線程通過C A S去刪除頭節(jié)點(diǎn),假設(shè)現(xiàn)在鏈表有A->B節(jié)點(diǎn)

java中CAS是什么

  • 線程1刪除A節(jié)點(diǎn),B節(jié)點(diǎn)成為頭節(jié)點(diǎn),正要執(zhí)行C A S(A,A,B)時(shí),時(shí)間片用完,切換到線程2

  • 線程2刪除A、B節(jié)點(diǎn)

  • 線程2加入C、A節(jié)點(diǎn),鏈表節(jié)點(diǎn)變成A->C

  • 線程1重新獲取時(shí)間片,執(zhí)行C A S(A,A,B)

  • 丟失C節(jié)點(diǎn)

要解決A B A問題也非常簡單,只要追加版本號即可,每次改變時(shí)加1,即A —> B —> A,變成1A —> 2B —> 3A,在Java中提供了AtomicStampedRdference可以實(shí)現(xiàn)這個(gè)方案(面試只要問了C A S,就一定會問ABA,這塊一定要搞明白)。

感謝各位的閱讀!關(guān)于“java中CAS是什么”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!


網(wǎng)頁名稱:java中CAS是什么
網(wǎng)站URL:http://weahome.cn/article/gjocch.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部