91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

java中CAS是什么

發布時間:2021-07-29 09:02:19 來源:億速云 閱讀:615 作者:小新 欄目:編程語言

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

前言

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

C A S作為并發編程必不可少的基礎知識,面試時C A S也是個高頻考點,所以說C A S是必知必會,本文將帶讀者們深入理解C A S

大綱

java中CAS是什么

C A S基本概念

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

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

java中CAS是什么

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

C A S如何保證原子性

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

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

  • 總線鎖定

  • 緩存鎖定

總線鎖定

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

java中CAS是什么

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

java中CAS是什么

緩存鎖定

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

所謂緩存鎖定是指C P U緩存行進行鎖定,當緩存行中的共享變量回寫到內存時,其他C P U會通過總線嗅探機制感知該共享變量是否發生變化,如果發生變化,讓自己對應的共享變量緩存行失效,重新從內存讀取最新的數據,緩存鎖定是基于緩存一致性機制來實現的,因為緩存一致性機制會阻止兩個以上C P U同時修改同一個共享變量(現代C P U基本都支持和使用緩存鎖定機制)。

C A S的問題

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

C A S的問題如下

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

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

  • ABA問題

只能保證一個共享變量原子操作

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

自旋時間太長

當一個線程獲取鎖時失敗,不進行阻塞掛起,而是間隔一段時間再次嘗試獲取,直到成功為止,這種循環獲取的機制被稱為自旋鎖(spinlock)。

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

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

最后來說自旋鎖的實現,實現自旋鎖可以基于C A S實現,先定義lockValue對象默認值11代表鎖資源空閑,0代表鎖資源被占用,代碼如下

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

        // 循環檢測嘗試獲取鎖
        while (!tryLock()){
            // 空轉
        }

    }
    
    //獲取鎖
    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實現的Integer原子操作類,還定義了3個函數lock、tryLock、unLock

tryLock函數-獲取鎖

  • 期望值1,更新值0

  • C A S更新

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

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

unLock函數-釋放鎖

  • 期望值0,更新值1

  • C A S更新

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

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

lock函數-自旋獲取鎖

  • 執行tryLock函數,返回true停止,否則一直循環

java中CAS是什么

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

ABA問題

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

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

只是簡單的數據結構,確實不會有什么問題,如果是復雜的數據結構可能就會有問題了(使用AtomicReference可以把C A S使用在對象上),以鏈表數據結構為例,兩個線程通過C A S去刪除頭節點,假設現在鏈表有A->B節點

java中CAS是什么

  • 線程1刪除A節點,B節點成為頭節點,正要執行C A S(A,A,B)時,時間片用完,切換到線程2

  • 線程2刪除A、B節點

  • 線程2加入C、A節點,鏈表節點變成A->C

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

  • 丟失C節點

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

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

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

铜鼓县| 榕江县| 威远县| 武义县| 黔东| 大邑县| 达拉特旗| 隆尧县| 白朗县| 浦江县| 延津县| 成安县| 上犹县| 会理县| 云南省| 乌鲁木齐县| 黄浦区| 张家港市| 浦北县| 冀州市| 富锦市| 新宁县| 博爱县| 金塔县| 三门县| 务川| 久治县| 邛崃市| 徐州市| 仲巴县| 大理市| 衡阳县| 金山区| 永德县| 鄂伦春自治旗| 惠东县| 泽普县| 临猗县| 新化县| 呈贡县| 隆尧县|