切換語言為:簡體

詳細介紹Java的AtomicInteger是如何保證執行緒安全

  • 爱糖宝
  • 2024-08-23
  • 2055
  • 0
  • 0

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 方法直接呼叫了 UnsafecompareAndSwapInt 方法,這個方法可以保證在硬體層面上的原子性操作。

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 在高併發環境下比傳統的同步機制更高效。

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.