一、什麼是CAS?
CAS(Compare And Swap),就是比較並交換,是解決多線程情況下,解決使用鎖造成性能損耗問題的一種機制。
CAS包含三個操作數:
- 變量內存位置(V)
- 預期的變量原值(A)
- 變量的新值(B)
當要對變量進行修改時,先會將內存位置的值與預期的變量原值進行比較,如果一致則將內存位置更新爲新值,否則不做操作,無論哪種情況都會返回內存位置當前的值。
二、CAS的實踐案例
整個JUC都是建立在CAS之上的,我們以Java8爲例,看看AtomicInteger
的CAS實現:
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
/**
* Unsafe類是提供了native方法,用於完成硬件級別的原子性操作
* 在這裏提供Unsafe.compareAndSwapInt方法來完成CAS的比較並更新
*/
private static final Unsafe unsafe = Unsafe.getUnsafe();
/**
* value在內存中的偏移量,是即CAS中的內存地址V
*/
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;
// 省略一大串代碼
/**
* 通過unsafe類提供的native方法完成CAS操作
*
* @param expect 預期的變量原值(A)
* @param update 變量的新值(B)
* @return {@code true} if successful. False return indicates that
* the actual value was not equal to the expected value.
*/
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
/**
* 進行CAS操作,自旋直到數據更新成功
*
* @param updateFunction a side-effect-free function
* @return 更新後的值
* @since 1.8
*/
public final int updateAndGet(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get();
next = updateFunction.applyAsInt(prev);
} while (!compareAndSet(prev, next));
return next;
}
}
compareAndSet的CAS實現:通過Unsafe的方法,調用native方法完成了硬件級別的原子性操作。
注意,Unsafe方法可能會在未來的jdk版本中移除,而且使用一旦出現問題可能就是JVM實例崩潰級別的問題,所以官方不推薦在應用代碼中使用。
三、CAS存在的問題
ABA問題:CAS在檢查值的時候,只會比較預期值A與內存位置的值是否相同,如果內存位置值,經過若干次修改又變回了A ( A -> B -> A),CAS檢查依舊會通過,但是實際上這個值已經修改過了。
解決方案:解決的思路就是引入類似樂觀鎖的版本號控制,不止比較預期值和內存位置的值,還要比較版本號是否正確。
實現案例:從JDK5開始,atomic包就提供了AtomicStampedReference
類來解決ABA問題,相較CAS引入了一個標誌,在比較完預期值與內存地址值之後,再對預期標誌和現有標誌做比較,都通過才執行更新操作。