介紹
AtomicBoolean 是使用CAS實現的對布林值進行原子更新的類。
什麼是CompareAndSwap(CAS)
? 即比較並替換,實現併發演算法時常用到的一種技術。CAS操作包含三個運算元——記憶體位置、預期原值及新值。執行CAS操作的時候,將記憶體位置的值與預期原值比較,如果相匹配,那麼處理器會自動將該位置值更新為新值,否則,處理器不做任何操作。CAS是一條CPU的原子指令(cmpxchg指令),不會造成所謂的資料不一致問題,
AtomicBoolean 呼叫
Unsafe 類提供的CAS方法(如compareAndSwapXXX)實現了原子操作。要了解 Unsafe 的基本運用,請檢視 《Unsafe的基本操作》
static { try { valueOffset = unsafe。objectFieldOffset (AtomicBoolean。class。getDeclaredField(“value”)); } catch (Exception ex) { throw new Error(ex); }}private volatile int value;
檢視原始碼可知:AtomicBoolean 類在例項化時會首先獲取 value 的偏移量(valueOffset),後續方法中 Unsafe 類都會根據 valueOffset 進行資料操作。
並且 value 需要宣告為
volatile
,以保證併發時執行緒間的可見性。
基本操作
以下以JDK 8中的原始碼進行示例。
1、建立 AtomicBoolean 例項
AtomicBoolean 提供了兩個構造方法可供使用,如下:
public AtomicBoolean(boolean initialValue) { value = initialValue ? 1 : 0;}public AtomicBoolean() {}
因此例項化 AtomicBoolean 時按需呼叫對應的建構函式即可。
2、獲取值
可以使用 get() 方法:
AtomicBoolean atomicBoolean = new AtomicBoolean();boolean value = atomicBoolean。get();System。out。println(value); // 輸出:false
3、使用 compareAndSet 進行原子更新
compareAndSet
原始碼如下:
public final boolean compareAndSet(boolean expect, boolean update) { int e = expect ? 1 : 0; int u = update ? 1 : 0; return unsafe。compareAndSwapInt(this, valueOffset, e, u);}
可知,該方法只會呼叫一次 CAS 方法進行原子更新,若失敗,則返回false,否則,返回 true;
但是不會進行失敗重試
。
原子更新還有一個
weakCompareAndSet
方法:
public boolean weakCompareAndSet(boolean expect, boolean update) { int e = expect ? 1 : 0; int u = update ? 1 : 0; return unsafe。compareAndSwapInt(this, valueOffset, e, u);}
由於其實現與
compareAndSet 一致,
因此,該方法呼叫結果也與
compareAndSet 一致。
4、設定值
可以使用 set() 方法對值進行重新設定,能保證執行緒可見性,非常簡單。
atomicBoolean。set(true);
也可以使用 lazySet() 進行值設定:
public final void lazySet(boolean newValue) { int v = newValue ? 1 : 0; unsafe。putOrderedInt(this, valueOffset, v);}
底層實現為 unsafe。putOrderedInt ,不保證執行緒可見性。
5、核心操作 getAndSet
以原子方式設定為給定值並返回前一個值,底層實現如下:
public final boolean getAndSet(boolean newValue) { boolean prev; do { prev = get(); } while (!compareAndSet(prev, newValue)); return prev;}
可知,底層使用迴圈不斷重試呼叫 compareAndSet ,直到 compareAndSet 返回 true(即設定成功)為止。
總結:在開發過程中,涉及到的核心方法是
getAndSet ,
可保證併發情況下的資料一致性。