CAS(Compare-And-Swap 或 Compare-And-Set)是一種用于實現并發編程中無鎖(lock-free)數據結構的原子操作。CAS 操作比較內存中的某個位置的當前值是否等于預期值,如果相等,則將其更新為新的值,否則不更新。整個過程是一個原子操作,不會被中斷,從而避免了線程同步中的競爭和死鎖問題。
CAS 的原理
CAS 操作包含三個操作數:
- 內存位置(V,Variable):需要更新的變量的內存地址。
- 期望值(A,Expected):當前線程認為這個變量應該具有的值。
- 新值(B,New):如果變量的當前值等于期望值,那么需要將變量更新為的新值。
CAS 操作的邏輯如下:
- 如果內存位置 V 的當前值等于期望值 A,那么將內存位置 V 的值更新為新值 B,返回 true 表示更新成功。
- 否則,不做任何操作,返回 false 表示更新失敗。
CAS 的步驟
- 讀取變量 V 的當前值。
- 比較變量 V 的當前值和期望值 A。
- 如果變量 V 的當前值等于期望值 A,將其更新為新值 B。
- 如果變量 V 的當前值不等于期望值 A,不進行更新。
這個過程是通過底層硬件的原子指令支持來實現的,因此是線程安全的。
CAS 的優點
- 無鎖并發:通過 CAS 操作,可以實現無鎖的數據結構,從而避免了傳統鎖機制帶來的開銷和死鎖問題。
- 高效:在大多數情況下,CAS 操作比使用鎖進行同步更加高效,特別是在多線程競爭不激烈的情況下。
CAS 的缺點
- ABA 問題:如果變量 V 的值從 A 變成 B,又變回 A,CAS 操作無法檢測到這種變化,從而誤認為沒有發生變化。ABA 問題可以通過版本號解決,即每次更新變量時同時更新版本號。
- 自旋等待:在高競爭環境下,如果多個線程頻繁失敗并重試 CAS 操作,會導致大量的 CPU 消耗。
- 復雜性:相較于使用鎖,編寫和維護 CAS 操作的代碼更為復雜。
Java 中的 CAS 實現
Java 提供了 java.util.concurrent.atomic
包中的類來支持 CAS 操作,如 AtomicInteger
、AtomicBoolean
、AtomicReference
等。這些類內部使用了 Unsafe 類的 CAS 方法來實現原子操作。
示例:AtomicInteger 的 CAS 操作
import java.util.concurrent.atomic.AtomicInteger;public class CASExample {public static void main(String[] args) {AtomicInteger atomicInteger = new AtomicInteger(0);int expectedValue = 0;int newValue = 1;boolean success = atomicInteger.compareAndSet(expectedValue, newValue);System.out.println("CAS operation success: " + success);System.out.println("Current value: " + atomicInteger.get());}
}
解決 ABA 問題
Java 提供了 AtomicStampedReference
類來解決 ABA 問題。它在進行 CAS 操作時,不僅比較值,還比較一個額外的標記(stamp)。
示例:使用 AtomicStampedReference 解決 ABA 問題
import java.util.concurrent.atomic.AtomicStampedReference;public class ABAExample {public static void main(String[] args) {AtomicStampedReference<Integer> atomicStampedRef = new AtomicStampedReference<>(100, 0);int[] stampHolder = new int[1];Integer currentValue = atomicStampedRef.get(stampHolder);int currentStamp = stampHolder[0];int newValue = 101;int newStamp = currentStamp + 1;boolean success = atomicStampedRef.compareAndSet(currentValue, newValue, currentStamp, newStamp);System.out.println("CAS operation success: " + success);System.out.println("Current value: " + atomicStampedRef.get(stampHolder) + ", Current stamp: " + stampHolder[0]);}
}
總結
CAS 是一種高效的無鎖并發機制,通過硬件支持的原子操作來實現線程安全。雖然 CAS 有一些缺點,但在合適的場景中,CAS 可以提供比鎖更好的性能和可擴展性。Java 提供了豐富的 CAS 支持類,開發者可以方便地使用這些類來實現高效的并發程序。