juc之volatile和CAS演算法
大家推薦個靠譜的公眾號程式設計師探索之路,大家一起加油,這個公眾號已經接入圖靈
之前一直有疑惑,volatile關鍵字時記憶體可見的為什麼改值的時候還得處理併發問題,今天終於搞懂了
1.volatile關鍵字能 保證 每次讀取的是最新的 但是如果有多個執行緒同時改變 值 還是不能保證執行緒安全
volatile缺點:
1.volatile 不具備“互斥性”
2.volatile 不能保證變數的原子性
2.CAS(compare-and-swap)是一種硬體對併發的支援,針對多處理器操作而設計的處理器中的一種特殊指令,用於管理對共享資料的併發訪問。
CAS是一種無鎖的非阻塞演算法的實現。
CAS包含了3個運算元
需要讀寫的記憶體值V
進行比較的值A
擬寫入的新值B
當且僅當V的值等於A時,CAS通過原子方式用新值B來更新V的值,否則不會執行任何操作。
spring cloud 中ribbon輪詢演算法中控制併發就是用的CAS演算法
當然裡面用的java提供的原理變數AtomicInteger, 在java.util.concurrent.atomic包下java提供了很多常用的原子變數
3.CAS缺點
CAS的缺點:
CAS雖然很高效的解決了原子操作問題,但是CAS仍然存在三大問題。
迴圈時間長開銷很大。
只能保證一個共享變數的原子操作。
ABA問題。
迴圈時間長開銷很大:
我們可以看到getAndAddInt方法執行時,如果CAS失敗,會一直進行嘗試。如果CAS長時間一直不成功,可能會給CPU帶來很大的開銷。
只能保證一個共享變數的原子操作:
當對一個共享變數執行操作時,我們可以使用迴圈CAS的方式來保證原子操作,但是對多個共享變數操作時,迴圈CAS就無法保證操作的原子性,這個時候就可以用鎖來保證原子性。
什麼是ABA問題?ABA問題怎麼解決?
如果記憶體地址V初次讀取的值是A,並且在準備賦值的時候檢查到它的值仍然為A,那我們就能說它的值沒有被其他執行緒改變過了嗎?
如果在這段期間它的值曾經被改成了B,後來又被改回為A,那CAS操作就會誤認為它從來沒有被改變過。這個漏洞稱為CAS操作的“ABA”問題。Java併發包為了解決這個問題,提供了一個帶有標記的原子引用類“AtomicStampedReference”,它可以通過控制變數值的版本來保證CAS的正確性。因此,在使用CAS前要考慮清楚“ABA”問題是否會影響程式併發的正確性,如果需要解決ABA問題,改用傳統的互斥同步可能會比原子類更高效。