天天看點

Java中的CAS原理

前言:在對AQS架構進行分析的過程中發現了很多CAS操作,是以有必要對CAS進行一個梳理,也便更清楚的了解其原理。

1.CAS是什麼

CAS,是compare and swap的縮寫,中文含義:比較交換。

CAS操作包含三個操作數——需要讀寫的記憶體值(V)、預期原值[進行比較的值](A)和新值(B)。如果V的值與A值比對時,那麼就将該記憶體位置的值更新為新值,否則不做任何操作。

CAS用于同步的方式是從位址V處讀取值A,在執行一些列計算後獲得新值B,如果此時記憶體V處的值和預期值A相等,則将V處值更新為B,此時CAS操作成功。

2.CAS原理

在intel的CPU中,Java CAS操作通過cmpxchg指令來完成原子操作,通過JNI來完成非阻塞算法,J.U.C包都建立在CAS上,對比synchronized阻塞算法,通過CAS在性能上有了很大的提升。

CAS的操作都集中在Unsafe類中,這裡看compareAndSwapInt的源碼:

Java中的CAS原理

通過源碼可以看出該方法為native的,它會去調底層的C++代碼。對應intel x86處理器源代碼片段:

Java中的CAS原理

os::is_MP()指令會根據目前處理器類型來決定是否為cmpxchg指令添加lock字首。如果是多處理器,就會在cmpxchg指令前加上lock字首,否則單處理器按書序一緻性執行,不需要記憶體屏障的效果。

3.CAS的缺點

CAS雖然可以很高效的解決原子操作問題,但它仍然存在三大問題。

#1.ABA問題

ABA問題産生的原因:CAS操作的時候需要檢查值有沒有發生變化,如果沒有發生變化則進行更新,但如果一個值原來是A,接着變成B,後來又變成A,在CAS操作的時候會發現它的值沒有發生變化,但實際上值發生了變化。是以這種操作是有問題的。

解決思路:使用版本号。在變量前面追加上版本号,每次變量更新的時候把版本号自增,那麼A-B-A 就會變成1A-2B-3A。從Java1.5開始JDK的atomic包裡提供了一個類AtomicStampedReference來解決ABA問題。這個類的compareAndSet方法作用是首先檢查目前引用是否等于預期引用,并且目前标志是否等于預期标志,如果全部相等,則以原子方式将該引用和該标志的值設定為給定的更新值。

#2.循環時間開銷大

自旋CAS如果長時間不成功,會給CPU帶來非常大的執行開銷。

#3.隻能保證一個共享變量的原子操作

因為Java中的CAS操作隻是對CPU的cmpxchg指令的一層封裝,它的功能就是一次隻能原子的修改一個變量,可以加鎖來解決這個問題。或者利用AtomicReference把多個變量放入一個對象中進行CAS操作。

總結

對于CAS記住比較交換,相同則更新,以及CAS的在AQS的重要地位。

參考:

https://blog.52itstyle.com/archives/948/

by Shawn Chen, 2019.1.30日,下午。

=========================================================

比你優秀的人比你還努力,你有什麼資格不去奮鬥!

__一個有理想的程式員。

cas

繼續閱讀