深入分析Java中CAS機制

2021-08-07 12:20:32 字數 2175 閱讀 7234

在jdk 1.5中增加的乙個最主要的支援是atomic類,比如說atomicinteger, atomiclong,這些類可幫助最大限度地減少在多執行緒中對於一些基本操作(例如,增加或減少多個執行緒之間共享的值)的複雜性。而這些類的實現都依賴於cas(compare and swap)的演算法。

但是,由於在程序掛起和恢復執行過程中存在著很大的開銷。當乙個執行緒正在等待鎖時,它不能做任何事,所以悲觀鎖有很大的缺點。舉個例子,如果乙個執行緒需要某個資源,但是這個資源的占用時間很短,當執行緒第一次搶占這個資源時,可能這個資源被占用,如果此時掛起這個執行緒,可能立刻就發現資源可用,然後又需要花費很長的時間重新搶占鎖,時間代價就會非常的高。

樂觀鎖思路就是,每次不加鎖而是假設沒有衝突而去完成某項操作,如果因為衝突失敗就重試,直到成功為止。某個執行緒可以不讓出cpu,而是一直while迴圈,如果失敗就重試,直到成功為止。所以,當資料爭用不嚴重時,樂觀鎖效果更好。比如cas就是一種樂觀鎖思想的應用。

cas中有三個核心引數:

1.主記憶體中存放的v值,所有執行緒共享。

3.需要寫入記憶體中並改寫v值的b值。也就是執行緒對a值操作後放入到主存v中。

上面說的比較抽象,看下面的這幅圖比較容易理解。

如上圖中,主存中儲存v值,執行緒中要使用v值要先從主存中讀取v值到執行緒的工作記憶體a中,然後計算後變成b值,最後再把b值寫回到記憶體v值中。多個執行緒共用v值都是如此操作。cas的核心是在將b值寫入到v之前要比較a值和v值是否相同,如果不相同證明此時v值已經被其他執行緒改變,重新將v值賦給a,並重新計算得到b,如果相同,則將b值賦給v。

如果不使用cas機制,看看存在什麼問題,假如v=1,現在thread1要對v進行加1,thread2也要對v進行加1,首先thread1讀取v=1到自己工作記憶體a中此時a=1,假設thread2此時也讀取v=1到自己的工作記憶體a中,分別進行加1操作後,兩個執行緒中b的值都為2,此時寫回到v中時發現v的值為2,但是兩個執行緒分別對v進行加處理結果卻只加了1有問題。

cas核心**

if (a==v)

else

return v;

上面的操作是原子操作,現在來看看如果兩個執行緒同時要對v進行加1操作使用上面的cas機制後能不能獲得正確結果。

①thread 1和thread2 要對v進行加1,thread1和thread2同時讀取v值並且對v執行加1操作。

初始值 v=1,a=0, b=0。
②假設thread1,thread 2先讀取v值賦給a,並且對a進行加1,得到b=2。

v=1,t1_a=1,t1_b=2;t2_a=1
thread1要將t1_b寫入v中,先要執行cas操作:

if (t1_a==v)

else

return v;

因為t1_a=1=v,所以執行 v=t1_b=2,此時v=2。

③thread2也要對v執行加操作。執行加操作之後

v=2 ,t2_a=1,t2_b=2,
當thread2要將t2_b值寫要v中之前要執行cas操作,

if (t2_a==v)

else

return v;

此時t2_a=1,v=2, t2_a!=v,這時候返回v=2,給t2_a,t2_a=v=2,然後再次對t2_a進行加1,得到t2_b,此時t2_b=3,t2_a=2,比較t2_a==v,所以將t2_b的值賦給t2_v,t2_v=t2_b=3。最後結果為3。正確。

如果一開始位置v得到的舊值是a,當進行賦值操作時再次讀取發現仍然是a,並不能說明變數沒有被其它執行緒改變過。有可能是其它執行緒將變數改為了b,後來又改回了a。大部分情況下aba問題不會影響程式併發的正確性,如果要解決aba問題,用傳統的互斥同步可能比原子類更高效。

在變數前面追加版本號:每次變數更新就把版本號加1,則a-b-a就變成1a-2b-3a。

atomic包下的atomicstampedreference類:其compareandset方法首先檢查當前引用是否等於預期引用,並且當前標誌是否等於預期標誌,如果全部相等,則以原子方式將該引用的該標誌的值設定為給定的更新值。

深入分析異常機制

我們知道c 和c最大的不同就是它更好的支援物件導向程式設計,封裝,多型,繼承,異常,命名空間.通用型程式設計等等.對於面向機制為什麼說是更好的支援哪.是因為用c同樣可以編寫物件導向程式設計.我們都知道c函式可以通過結構體和函式指標來設計一些低階的類.但c 提供的class則更好的維護了資料的隱藏.而...

深入分析java執行緒中的volatile

平時在閱讀jdk原始碼的時候,經常看到原始碼中有寫變數被volatile關鍵字修飾,但是卻不是十分清除這個關鍵字到底有什麼用處,現在終於弄清楚了,那麼我就來講講這個volatile到底有什麼用吧。當乙個變數被定義為volatile之後,就可以保證此變數對所有執行緒的可見性,即當乙個執行緒修改了此變數...

C 中const的實現機制深入分析

c語言以及c 語言中的const究竟表示什麼?其具體的實現機制又是如何實現的呢?本文將對這兩個問題進行一些分析,需要了解的朋友可以參考下 問題 c語言以及c 語言中的const究竟表示什麼?其具體的實現機制又是如何實現的呢?本文將對這兩個問題進行一些分析,簡單解釋const的含義以及實現機制。問題分...