併發程式設計(五) CAS

2022-08-10 21:00:27 字數 2253 閱讀 6895

在atomic包中,大多數類都是借助unsafe類來實現的,如以下**

public

static atomicinteger count = new atomicinteger(0);

private

static

void

add()

incrementandget()方法的實現如下:

public

final

intincrementandget()

我們再繼續深入getandint()方法,實現如下:

public

final

int getandaddint(object var1, long var2, int

var4)

while(!this.compareandswapint(var1, var2, var5, var5 +var4));

return

var5;

}

在以上**中我們著重要說的是 compareandswapint(var1, var2, var5, var5 + var4) 這個方法,compareandswap,取每個單詞首寫字母,就是我們經常說的cas。這個方法中有四個引數var1為當前物件,即**中的count,var2為當前值,如想計算2加上1等於3的操作,var2即為2,var4為增加量,也就是這個例子中的1,var5為呼叫底層方法得到的底層當前的值,如果沒有其他執行緒改變底層當前值,返回為2,compareandswapint方法的作用為,如果var2(當前值)與var5(底層當前值相等)則將底層值覆蓋為底層當前值(var5)+增加量(var4),否則(其他執行緒更改了底層當前值,var5不等於var2),重新從底層方法取一次var5的值,如此時var5=4,並重新從var1(當前物件)取一次var2的值,如此時var2的值也變為4,則採取相加操作覆蓋底層值,如果var2與var5仍不等,則繼續迴圈取值,直到相等為止。 

總結一下,cas操作包含三個運算元,記憶體位置(v),預期原值(a)和新值(b),如果記憶體位置的值與預期原值相匹配,處理器會自動將該位置值更新為新值,否則處理器不做任何操作。cas指令一般都返回該位置的值(有特殊情況只返回是否成功),cas簡而言之就是,我認為位置v應該包含值a,如果包含該值,就將b放到這個位置,否則不更改該位置的值,只告訴我這個位置現在的值即可 。

對於getintvolatile方法和compareandswapint的實現如下:

public

native

int getintvolatile(object var1, long var2);

public

final

native

boolean compareandswapint(object var1, long var2, int var4, int var5);

可將兩個方法都由native修飾,native修飾的方法為底層方法,一般由c語言來實現。

鎖分為悲觀鎖和樂觀鎖,獨佔鎖是一種悲觀鎖,synchronized是一種獨佔鎖,如果鎖被占用,其他需要鎖的執行緒就會被掛起,直到持有鎖的執行緒釋放鎖,它會產生的問題如下:

a、在多執行緒競爭下,加鎖釋放鎖會導致比較多的上下文切換和排程延時,引起效能問題

b、如果乙個優先順序高的執行緒等待乙個優先順序低的執行緒釋放鎖會導致優先順序倒置,引起效能風險

另一種就是樂觀鎖,它每次執行時並不加鎖而是假設沒有衝突的去完成操作,如果因為衝突失敗就重試,直到成功為止,而客觀鎖用到的機制就是cas。雖然cas可以很高效的解決原子操作,但是cas仍然存在三大問題:

a、aba問題,如果乙個值原來是a,後被改成b,之後又改為a,那麼使用cas進行檢查時發現它的值並沒有發生變化,但是實際上卻發生變化了,aba問題的解決思路就是使用版本號,在變數面前加上版本號,每次變數更新的時候把版本加一,上面部落格中我們提到atomic包中有專門的類來解決aba問題

b、迴圈時間長開銷大。cas迴圈如果長時間不成功,會給cpu帶來非常大的執行開銷。如果jvm能支援處理器提供的pause指令則效率會有一定的提公升,pause指令有兩個作用,推遲流水線執行,使cpu不會消耗過多的執行資源和避免退出迴圈的時候因記憶體順序衝突而引起cpu流水線被清空,提高cpu執行效率

c、只能保證乙個共享變數的原子操作。當對乙個共享變數執行操作時,我們可以使用迴圈cas來保證原子操作,但是對多個共享變數操作時,迴圈cas就無法保證操作的原子性,這個時候可以用鎖或把多個共享變數合併成乙個共享變數來操作或者把多個變數放在乙個物件裡(atomic包中有對引用型別的原子操作)來進行cas操作

併發程式設計cas的aba問題

多執行緒環境下,兩個執行緒a,b可能會對共享資料m進行操作。為了保證乙個執行緒在讀到資料跟寫入資料之間沒有被其他執行緒修改過,使用cas解決。cas 更改之前先判斷舊值是否有變化,如果沒有變化,認為沒有執行緒對該共享值做過操作。這種認為是有一下問題的,時執行緒a 執行緒bt1 讀m值為1 t2讀m值...

Go併發程式設計之CAS操作

一 前言 go語言類似j a juc包也提供了一些列用於多執行緒之間進行同步的措施,比如低階的同步措施有 鎖 cas 原子變數操作類。相比j a來說go提供了獨特的基於通道的同步措施。我們先來看看go中cas操作 二 cas操作 go中的cas操作與j a中類似,都是借用了cpu提供的原子性指令來實...

java 併發程式設計 顯示鎖和CAS

lock 介面可以提供一些sychnoized 不具備的一些其他特性 如 1。嘗試非阻塞去獲取鎖 2.可以被終端的獲取鎖 3.超時獲取鎖 lock 介面的核心方法 lock 獲取鎖,類似sychnonized 關鍵字 unlock 釋放鎖 當退出synchnonized 關鍵字所包圍的 塊的時候,鎖...