CAS是什么?
CAS是什么
CAS是Compare-And-Swap(比較并交換)的縮寫,是一種輕量級的同步機制,主要用于實現多線程環境下的無鎖算法和數據結構,保證了并發安全性,它可以在不適用鎖的情況下,對共享數據進行線程安全的操作。(ConcurentHashMap在JDK1.8開始使用的是CAS)
CAS操作主要有三個參數:要更新的內存位置、期望的值和新值。CAS操作的執行過程如下:
- 1、首先,獲取要更新的內存位置,記為var
- 2、然后,將期望值expected與var進行比較,如果兩者相等,則將內存位置的值var更新為新值new
- 3、如果兩者不相等,則說明有其他線程修改了內存位置的值var,此時CAS操作失敗,需要重新嘗試。
原理相關的Unsafe類
Unsafe類是JDK提供的不安全的類,提供了一些底層操作,包括內存操作、線程調度、對象實例化等。他的作用是讓Java可以在底層直接操作內存,從而提高程序的效率。但是,Unsafe類是不安全的,所以只有JDK開發員才使用他,普通開發不建議使用。
由于CAS操作時基于底層硬件支持的原子性指令來實現的,所以它可以保證操作的原子性和線程安全性,同時也可以避免使用鎖帶來的性能開銷。CAS主要用于并發編程中,比如實現無鎖數據結構、實現線程安全的計數器等。
什么時ABA
ABA問題就是在CAS操作過程中,如果變量的值被從A改為B又改為A,而CAS操作是能夠成功的,這就可能導致程序出現意外的結果。
解決方案
Java的AtomicStampedReference類,該類通過使用版本號的方式來解決ABA問題,每個共享變量都會關聯一個版本號,CAS操作時需要同時檢查值和版本號是否匹配。因此,如果共享變量被改變了,版本號就會發生變化,即使共享變量變為原來的值,版本號不同,CAS操作會失敗。
CPU空轉
為什么出現CPU空轉
如果某個線程一直在自旋等待,會浪費CPU資源。
解決
當一個線程請求獲取鎖時,如果已經持有鎖,那就計數器加1,否則使用CAS操作獲取鎖,避免使用synchronized關鍵字或ReentrantLock等鎖的實現機制。
當線程獲取失敗,自旋等待,避免立刻進入阻塞狀態,避免線程上下文的開銷,當重試小于10時,使用自旋方式,當重試次數大于10時,就阻塞等待,這樣可以在多線程環境下保證線程的公平性和效率。
釋放鎖時,如果計數器大于0,就減一,釋放一次減一次,否則將鎖的擁有者設置為null,喚醒其他線程。這樣確保在多個線程持有鎖的情況下,正確釋放鎖資源,并喚醒其他等待線程,保證線程正確性和公平性。
應用場景
在并發編程中廣泛應用,通常實現樂觀鎖和無鎖算法:
1、線程安全計數器
2、隊列:并發編程中,隊列經常用于線程之間的數據交換。使用CAS可以實現無鎖的非阻塞隊列。
3、數據庫并發控制
4、自旋鎖
5、線程池:多線程編程中,線程池可以提高線程的使用效率,使用CAS操作可以避免對線程池的加鎖,從而提高線程池的并發性能。
CAS真的完全沒加鎖嗎?
CAS是一個無鎖機制的操作,底層是通過Unsafe類使用native本地方法進行CAS操作,但是硬件層面CAS是如何保證原子性?真的完全沒加鎖嗎?
底層來看,CAS操作通常使用cmpxchg指令實現的。
這個指令如何保證原子性?
- 1、cmpxchg指令是一個原子指令,在CPU執行cmpxchg指令時,處理器會自動鎖定總線,防止其他CPU訪問共享變量,然后執行比較和交換操作,最后釋放總線。
- 2、cmpxchg指令在執行期間,CPU會自動禁止中斷。這樣確保CAS原子性,避免中斷和其他干擾對操作的影響。
- 3、cmpxchg指令是硬件實現的,可以保證原子性和正確性。CPU中的硬件電路確保了cmpxchg指令的正確執行,以及對共享變量的訪問是原子的。
所以操作系統層面,CAS會加鎖,通過加鎖的方式鎖定總線,避免其他CPU訪問共享變量。
posted on 2023-11-28 22:49 zhizhizaide 閱讀(159) 評論(0) 收藏 舉報
浙公網安備 33010602011771號