Java併發編程—AtomicInteger 原理剖析

1、前言

AtomicInteger 是一個支持原子操做的 Integer 類,它提供了原子自增方法、原子自減方法以及原子賦值方法等。其底層是經過 volatile 和 CAS 實現的,其中 volatile 保證了內存可見性,CAS 算法保證了原子性。所以接下來咱們先了解下 volatile 和 CAS,而後在研究下 AtomicInteger 的源碼。java

2、volatile 變量

volatile 是一種稍弱的同步機制,用來確保將變量的更新操做通知到其餘線程。當把變量聲明爲 volatile 類型後,編譯器與運行時都會注意到這個變量是共享的,所以不會將該變量上的操做與其餘內存操做一塊兒重排序。volatile 變量不會被緩存在寄存器或者對其餘處理器不可見的地方,所以在讀取 volatile 類型的變量時總返回最新寫入的值。在訪問 volatile 變量時不會執行加鎖操做,所以也就不會使執行線程阻塞,所以 volatile 變量是一種比 sychronized 關鍵字更輕量級的同步機制。算法

3、CAS

CAS(Compare And Swap)即比較並交換,CAS 是樂觀鎖技術,當多個線程嘗試使用 CAS 同時更新同一個變量時,只有其中一個線程能更新變量的值,而其它線程都失敗,失敗的線程並不會被掛起,而是被告知此次競爭中失敗,並能夠再次嘗試。它包含三個參數:V 內存值,預期值 A,要修改的新值 B。當且僅當預期值 A 和內存值 V 相同時,將內存值 V 修改成 B,不然什麼都不作。原理圖以下所示:緩存


4、AtomicInteger 源碼剖析

private static final Unsafe unsafe = Unsafe.getUnsafe();//調用指針類Unsafe
private static final long valueOffset;//變量value的內存偏移量

static {
    try {
        valueOffset = unsafe.objectFieldOffset
            (AtomicInteger.class.getDeclaredField("value"));
    } catch (Exception ex) { throw new Error(ex); }
}

private volatile int value;//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) {//最終把值設置爲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) {//若是當前值爲expect,則設置爲update
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}複製代碼
public final int getAndIncrement() {//當前值加1返回舊值
    return unsafe.getAndAddInt(this, valueOffset, 1);
}


public final int getAndDecrement() {//當前值減1返回舊值
    return unsafe.getAndAddInt(this, valueOffset, -1);
}


public final int getAndAdd(int delta) {//當前值增長delta,返回舊值
    return unsafe.getAndAddInt(this, valueOffset, delta);
}


public final int incrementAndGet() {//當前值增長1返回新值
    return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}


public final int decrementAndGet() {//當前值減1,返回新值
    return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
}複製代碼

5、總結

使用 AtomicInteger 替換普通 int 類型執行自增的原子操做,可以保證了線程安全。安全

相關文章
相關標籤/搜索