AtomicBoolean操作詳解及原理分析

介紹

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 ,

可保證併發情況下的資料一致性。