CAS概述、定義、缺點和優化

1.CAS概述

CAS(Compare-and-Swap),即比較並替換,是一種實現併發算法時常用到的技術,Java併發包中的很多類都使用了CAS技術.

2. CAS定義

CAS需要有3個操作數:內存地址V,舊的預期值A,即將要更新的目標值B。
CAS指令執行時,當且僅當內存地址V的值與預期值A相等時,將內存地址V的值修改爲B,否則就什麼都不做。整個比較並替換的操作是一個原子操作。

3. CAS的缺點

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

  1. 循環時間長開銷很大.
  2. 只能保證一個共享變量的原子操作.
  3. ABA問題.

3.1 循環時間長開銷很大

我們可以看到getAndAddInt方法執行時,如果CAS失敗,會一直進行嘗試。如果CAS長時間一直不成功,可能會給CPU帶來很大的開銷

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

當對一個共享變量執行操作時,我們可以使用循環CAS的方式來保證原子操作,但是對多個共享變量操作時,循環CAS就無法保證操作的原子性,這個時候就可以用鎖來保證原子性。

3.3 ABA問題

問題:如果內存地址V初次讀取的值是A,並且在準備賦值的時候檢查到它的值仍然爲A,那我們就能說它的值沒有被其他線程改變過了嗎?
解釋:如果在這段期間它的值曾經被改成了B,後來又被改回爲A,那CAS操作就會誤認爲它從來沒有被改變過。這個漏洞稱爲CAS操作的“ABA”問題
解決:Java併發包爲了解決這個問題,提供了一個帶有標記的原子引用類“AtomicStampedReference”,它可以通過控制變量值的版本來保證CAS的正確性。因此,在使用CAS前要考慮清楚“ABA”問題是否會影響程序併發的正確性,如果需要解決ABA問題,改用傳統的互斥同步可能會比原子類更高效.

4. CAS優化(Java8)

問題:由於線程太密集了,太多人想要修改 i 的值了,進而大部分人都會修改不成功,白白着在那裏循環消耗資源
解決:爲了解決這個問題,Java8 引入了一個 cell[] 數組,它的工作機制是這樣的:假如有 5 個線程要對 i 進行自增操作,由於 5 個線程的話,不是很多,起衝突的機率較小,那就讓他們按照以往正常的那樣,採用 CAS 來自增吧。但是,如果有 100 個線程要對 i 進行自增操作的話,這個時候,衝突就會大大增加,系統就會把這些線程分配到不同的 cell 數組元素去,假如 cell[10] 有 10 個元素吧,且元素的初始化值爲 0,那麼系統就會把 100 個線程分成 10 組,每一組對 cell 數組其中的一個元素做自增操作,這樣到最後,cell 數組 10 個元素的值都爲 10,系統在把這 10 個元素的值進行彙總,進而得到 100,二這,就等價於 100 個線程對 i 進行了 100 次自增操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章