AtomicInteger
是 Java 併發包 java.util.concurrent.atomic
中的一個類,它提供了對 int
型別變數的原子操作。透過使用底層的硬體原語(如CAS操作),AtomicInteger
能夠保證對其操作的執行緒安全性,而不需要顯式使用鎖。
CAS 操作
CAS(Compare-And-Swap)是一種原子操作,它包含三個運算元——記憶體地址、預期值和新值。CAS 操作會比較記憶體地址中的當前值與預期值,如果兩者相等,則將該位置更新為新值;否則,不進行任何操作。整個過程是不可中斷的,因此能夠保證執行緒安全。
底層實現
1. 成員變數和構造方法
public class AtomicInteger extends Number implements java.io.Serializable { private static final long serialVersionUID = 6214790243416807050L; // Unsafe 例項,用於執行底層的CAS操作 private static final Unsafe unsafe = Unsafe.getUnsafe(); // value 欄位在記憶體中的偏移量 private static final long valueOffset; // 初始化 value 欄位的記憶體偏移量 static { try { valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } // volatile 修飾的 int 值,確保對該值的修改對所有執行緒可見 private volatile int value; public AtomicInteger(int initialValue) { value = initialValue; } public AtomicInteger() { } }
這裏,我們看到 AtomicInteger
使用了 sun.misc.Unsafe
類來進行低階別的原子操作。此外,value
欄位被 volatile
修飾,以確保其修改對所有執行緒立即可見。
2. 核心方法:compareAndSet
public final boolean compareAndSet(int expect, int update) { return unsafe.compareAndSwapInt(this, valueOffset, expect, update); }
compareAndSet
方法直接呼叫了 Unsafe
的 compareAndSwapInt
方法,這個方法可以保證在硬體層面上的原子性操作。
3. 常用方法
get 和 set
public final int get() { return value; } public final void set(int newValue) { value = newValue; }
這些方法分別用於獲取和設定當前值,其中 get
方法確保返回最新的值,而 set
方法則直接將新值賦給 value
。
incrementAndGet 和 decrementAndGet
public final int incrementAndGet() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return next; } } public final int decrementAndGet() { for (;;) { int current = get(); int next = current - 1; if (compareAndSet(current, next)) return next; } }
這些方法透過迴圈和 CAS 操作來實現自增和自減功能。如果 compareAndSet
操作失敗(說明有其他執行緒修改了 value
),則重新讀取當前值並重試,直到成功為止。
addAndGet 和 getAndAdd
public final int addAndGet(int delta) { for (;;) { int current = get(); int next = current + delta; if (compareAndSet(current, next)) return next; } } public final int getAndAdd(int delta) { for (;;) { int current = get(); int next = current + delta; if (compareAndSet(current, next)) return current; } }
這兩個方法實現了加法操作,並返回相應的結果。addAndGet
返回的是加法操作後的新值,而 getAndAdd
返回的是加法操作前的舊值。
4. Unsafe 類的使用
AtomicInteger
依賴於 Unsafe
類來實現底層的原子操作。Unsafe
類提供了一組硬體級別的操作,可以直接操作記憶體和物件。以下是 compareAndSwapInt
方法的定義:
public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);
這個方法是一個本地方法,透過JNI(Java Native Interface)呼叫底層的硬體指令來實現原子性操作。
5. compareAndSwapInt 分析
此方法的具體實現是在 JVM 的原生代碼中完成的,這通常是用 C 或 C++ 編寫的。
底層實現
compareAndSwapInt
的具體實現因 JVM 的實現和執行的平臺不同而有所差異。以 OpenJDK 為例,在 HotSpot JVM 中,compareAndSwapInt
的實現可以在以下檔案中找到:
對於64位架構:
src/hotspot/share/runtime/atomic.cpp
對於32位架構:
src/hotspot/os_cpu/linux_x86/atomic_linux_x86.inline.hpp
基於x86架構的CAS操作
以 x86 架構為例,底層硬體指令 CMPXCHG
(比較並交換)用於實現 CAS 操作。以下是一個虛擬碼示例,展示瞭如何在 C++ 中實現 compareAndSwapInt
:
inline bool compareAndSwapInt(jobject obj, jlong offset, jint expected, jint x) { jint* addr = (jint*)((char*)obj + offset); // 計算物件欄位的真實地址 return __sync_bool_compare_and_swap(addr, expected, x); // 使用 GCC 提供的內建函式 }
在這個虛擬碼中,__sync_bool_compare_and_swap
是 GCC 提供的內建函式,它生成適當的機器指令來實現 CAS 操作。相應的彙編指令可能類似這樣:
mov eax, expected ; 將預期值載入到EAX暫存器中 mov ebx, new_value ; 將新值載入到EBX暫存器中 lock cmpxchg [addr], ebx ; 嘗試將EBX的值交換到[addr]位置,如果EAX與[addr]內容相同
彙編級別的細節
以下是一個簡化的示例,展示了 x86 彙編中的 CMPXCHG
指令:
; 輸入: ; EAX: 預期值 ; EBX: 新值 ; [ECX]: 記憶體地址 lock cmpxchg [ecx], ebx ; 如果 [ecx] == eax,則 [ecx] = ebx,否則 eax = [ecx]
如果記憶體地址 ecx
中的值與 eax
中的值相等,那麼將 ebx
中的值寫入 ecx
指向的記憶體地址;否則,將 ecx
指向的記憶體地址中的值載入到 eax
中。整個操作在硬體層面上是原子的。
總結
AtomicInteger
透過 Unsafe
類提供的原子性操作實現了執行緒安全的整數操作。它使用 volatile
保證記憶體可見性,透過 CAS 操作(如 compareAndSet
)實現無鎖的執行緒安全。這使得 AtomicInteger
在高併發環境下比傳統的同步機制更高效。