一、核心概念
1 - CAS
CAS(Compare-And-Swap,比較并交換)操作是一種無鎖的原子操作,它在多線程環境下能夠保證線程安全,主要是通過硬件級別的原子性以及樂觀鎖的思想來實現的。以下詳細介紹 CAS 操作保證線程安全的原理:
1. CAS 操作的基本概念
CAS 操作包含三個操作數:內存位置(V)、預期原值(A)和新值(B)。其操作過程如下:
- 首先從內存位置 V 讀取當前值。
- 然后將讀取到的值與預期原值 A 進行比較。
- 如果當前值與預期原值相等,即 V == A,那么將內存位置 V 的值更新為新值 B。
- 如果當前值與預期原值不相等,即 V != A,那么不進行更新操作,通常會返回失敗信息。
在 Java 中,sun.misc.Unsafe
?類提供了一些基于 CAS 的操作方法,例如?compareAndSwapInt
、compareAndSwapLong
?等,AtomicInteger
?等原子類就是基于這些方法實現的。
2. 硬件級別的原子性
CAS 操作的原子性是由硬件保證的。在現代 CPU 中,CAS 操作是一個原子指令,這意味著在執行 CAS 操作時,不會被其他線程的操作所中斷。例如,當一個線程執行 CAS 操作時,其他線程無法同時修改該內存位置的值,從而保證了操作的原子性。
以?AtomicInteger
?的?incrementAndGet
?方法為例(簡化后的代碼):
public final int incrementAndGet() {for (;;) {int current = get();int next = current + 1;if (compareAndSet(current, next))return next;}
}public final boolean compareAndSet(int expect, int update) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
在?incrementAndGet
?方法中,通過不斷嘗試 CAS 操作來更新?AtomicInteger
?的值。由于 CAS 操作的原子性,即使多個線程同時執行該方法,也不會出現數據競爭的情況。
3. 樂觀鎖的思想
CAS 操作基于樂觀鎖的思想,它假設在大多數情況下,線程在嘗試更新數據時不會發生沖突。每個線程在更新數據之前,先檢查內存中的值是否與自己預期的值相等,如果相等則進行更新,否則重試。
這種樂觀的方式減少了線程之間的競爭,因為不需要像悲觀鎖(如?synchronized
?關鍵字)那樣在操作數據之前就鎖定數據,從而提高了并發性能。例如,在一個多線程環境中,多個線程同時對一個共享變量進行自增操作,如果使用悲觀鎖,每次只有一個線程能夠進行操作,其他線程需要等待;而使用 CAS 操作,多個線程可以同時嘗試更新,只有在發生沖突時才需要重試,大大提高了并發效率。
4. 解決 ABA 問題
雖然 CAS 操作能保證線程安全,但存在 ABA 問題,即一個值原來為 A,被一個線程修改為 B,然后又被另一個線程修改回 A,此時 CAS 操作可能會誤認為值沒有被修改而成功更新。為了解決 ABA 問題,可以使用帶有版本號的原子類(如?AtomicStampedReference
),在每次修改值時同時更新版本號,這樣在進行 CAS 操作時,不僅要比較值,還要比較版本號,從而避免 ABA 問題。
綜上所述,CAS 操作通過硬件級別的原子性以及樂觀鎖的思想,在多線程環境下保證了線程安全,并且在提高并發性能方面具有很大的優勢。
2 - AQS
3 -?與synchronized
的對比
特性 | synchronized | ReentrantLock |
---|---|---|
可重入性 | 支持 | 支持 |
鎖類型 | 非公平鎖(無法指定公平性) | 可選擇公平鎖或非公平鎖 |
鎖的獲取方式 | 自動獲取和釋放(基于代碼塊) | 需手動調用?lock() ?和?unlock() |
中斷響應 | 不支持 | 支持(lockInterruptibly() ) |
超時獲取鎖 | 不支持 | 支持(tryLock(long, TimeUnit) ) |
條件變量(Condition) | 通過?wait() /notify() ?實現 | 支持多個?Condition |