簡述java中cas
阿新 • • 發佈:2018-12-20
cas原理
cas是compareAndSwap的縮寫,可以看出就是比較比替換的意思。cas中有三個值,記憶體值V,舊的預期值E,更新值U,當且僅當V==E時,才進行更新,否則返回V。
cas應用
以java.util.concurrent包中的AtomicInteger為例。先演示程式碼:
public class AtomicIntegerTest { private static AtomicInteger atomicInteger=new AtomicInteger(5);//設定初始值 public static void main(String[] args) { atomicInteger.compareAndSet(0,1);//0!=5,不變 atomicInteger.compareAndSet(2,3);//2!=5,不變 atomicInteger.compareAndSet(3,4);//3!=5,不變 atomicInteger.compareAndSet(5,2);//5==5,更新為2 atomicInteger.compareAndSet(0,4);//0!=2,不變 System.out.println("result:"+atomicInteger.get()); } }
輸出結果是:result:2
原始碼:
/**使用 Unsafe.compareAndSwapInt()進行更新*/ private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; /**靜態程式碼塊對valueOffset進行初始化*/ static { try { valueOffset = unsafe.objectFieldOffset (java.util.concurrent.atomic.AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } /**使用volatile修飾value,保證value值的一致性*/ private volatile int value; /** * 有參構構造方法 */ public AtomicInteger(int initialValue) { value = initialValue; } /** * 無參構造方法 */ public AtomicInteger() { } /** * 獲取值 */ public final int get() { return value; } /** * 設定值 */ public final void set(int newValue) { value = newValue; } /** * 最終設定為給定值。 */ public final void lazySet(int newValue) { unsafe.putOrderedInt(this, valueOffset, newValue); } /** * 原子地設定為給定值並返回舊值。 * */ public final int getAndSet(int newValue) { return unsafe.getAndSetInt(this, valueOffset, newValue); } /** * * 若當前值等於期望的值,則更新給定的更新值 * */ public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); } /** *自增1 * */ public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; } /** * 自減1 * */ public final int decrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, -1) - 1; } /** * 增加給定的值 * */ public final int addAndGet(int delta) { return unsafe.getAndAddInt(this, valueOffset, delta) + delta; } /** * 更新並返回原先的值 */ public final int getAndUpdate(IntUnaryOperator updateFunction) { int prev, next; do { prev = get(); next = updateFunction.applyAsInt(prev); } while (!compareAndSet(prev, next)); return prev; } /** * 返回更新之後的值 */ public final int updateAndGet(IntUnaryOperator updateFunction) { int prev, next; do { prev = get(); next = updateFunction.applyAsInt(prev); } while (!compareAndSet(prev, next)); return next; }
原子包還有以下,用法基本一樣。
cas中的ABA問題
CAS可以有效的提升併發的效率,但同時也會引入ABA問題。
如執行緒1從記憶體X中取出A,這時候另一個執行緒2也從記憶體X中取出A,並且執行緒2進行了一些操作將記憶體X中的值變成了B,然後執行緒2又將記憶體X中的資料變成A,這時候執行緒1進行CAS操作發現記憶體X中仍然是A,然後執行緒1操作成功。雖然執行緒1的CAS操作成功,但是整個過程就是有問題的。比如連結串列的頭在變化了兩次後恢復了原值,但是不代表連結串列就沒有變化。
所以JAVA中提供了AtomicStampedReference/AtomicMarkableReference