本文首發於一世流雲的專欄: https://segmentfault.com/blog...
AtomicInteger,應該是atomic框架中用得最多的原子類了。顧名思義,AtomicInteger是Integer類型的線程安全原子類,能夠在應用程序中以原子的方式更新int值。java
先來看下AtomicInteger對象的建立。segmentfault
AtomicInteger提供了兩個構造器,使用默認構造器時,內部int類型的value值爲0:AtomicInteger atomicInt = new AtomicInteger();
api
AtomicInteger類的內部並不複雜,全部的操做都針對內部的int值——value,並經過Unsafe類來實現線程安全的CAS操做:
緩存
來看下面這個示例程序:安全
public class Main { public static void main(String[] args) throws InterruptedException { AtomicInteger ai = new AtomicInteger(); List<Thread> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { Thread t = new Thread(new Accumlator(ai), "thread-" + i); list.add(t); t.start(); } for (Thread t : list) { t.join(); } System.out.println(ai.get()); } static class Accumlator implements Runnable { private AtomicInteger ai; Accumlator(AtomicInteger ai) { this.ai = ai; } @Override public void run() { for (int i = 0, len = 1000; i < len; i++) { ai.incrementAndGet(); } } } }
上述代碼使用了AtomicInteger的incrementAndGet方法,以原子的操做對int值進行自增,該段程序執行的最終結果爲10000(10個線程,每一個線程對AtomicInteger增長1000),若是不使用AtomicInteger,使用原始的int或Integer,最終結果值可能會小於10000(併發時讀到了過期的數據或存在值覆蓋的問題)。併發
咱們來看下incrementAndGet內部:
oracle
內部調用了Unsafe類的getAndAddInt方法,以原子方式將value值增長1,而後返回增長前的原始值。框架
注意,上述是JDK1.8的實現,在JDK1.8以前,上述方法採用了自旋+CAS操做的方式:ide
public final int getAndIncrement() { for (;;) { int current = get(); int next = current + 1; if (compareAndSet(current, next)) return current; } }
AtomicInteger中有一個比較特殊的方法——lazySet:
性能
lazySet方法是set方法的不可見版本。什麼意思呢?
咱們知道經過volatile修飾的變量,能夠保證在多處理器環境下的「可見性」。也就是說當一個線程修改一個共享變量時,其它線程能當即讀到這個修改的值。volatile的實現最終是加了內存屏障:
lazySet內部調用了Unsafe類的putOrderedInt方法,經過該方法對共享變量值的改變,不必定能被其餘線程當即看到。也就是說以普通變量的操做方式來寫變量。
爲何會有這種奇怪方法?什麼狀況下須要使用lazySet呢?
考慮下面這樣一個場景:
private AtomicInteger ai = new AtomicInteger(); lock.lock(); try { // ai.set(1); } finally { lock.unlock(); }
因爲鎖的存在:
因此,上述ai.set(1)
能夠用ai.lazySet(1)
方法替換:
由鎖來保證共享變量的可見性,以設置普通變量的方式來修改共享變量,減小沒必要要的內存屏障,從而提升程序執行的效率。
方法聲明 | 描述 |
---|---|
int accumulateAndGet(int x, IntBinaryOperator accumulatorFunction) | 使用IntBinaryOperator 對當前值和x進行計算,並更新當前值,返回計算後的新值 |
int addAndGet(int delta) | 以原子方式將給定值與當前值相加,返回相加後的新值 |
boolean compareAndSet(int expect, int update) | 若是當前值 == expect,則以原子方式將該值設置爲給定的更新值(update) |
int decrementAndGet() | 以原子方式將當前值減 1,返回新值 |
int get() | 獲取當前值 |
int getAndAccumulate(int x, IntBinaryOperator accumulatorFunction) | 使用IntBinaryOperator 對當前值和x進行計算,並更新當前值,返回計算前的舊值 |
int getAndAdd(int delta) | 以原子方式將給定值與當前值相加,返回舊值 |
int getAndDecrement() | 以原子方式將當前值減 1,返回舊值 |
int getAndIncrement() | 以原子方式將當前值加 1,返回舊值 |
int getAndSet(int newValue) | 以原子方式設置爲給定值,並返回舊值 |
int getAndUpdate(IntUnaryOperator updateFunction) | 使用IntBinaryOperator 對當前值進行計算,並更新當前值,返回計算前的舊值 |
int incrementAndGet() | 以原子方式將當前值加 1,返回新值 |
void lazySet(int newValue) | 設置爲給定值,但不保證值的改變被其餘線程當即看到 |
void set(int newValue) | 設置爲給定值 |
int updateAndGet(IntUnaryOperator updateFunction) | 使用IntBinaryOperator 對當前值進行計算,並更新當前值,返回計算後的新值 |
boolean weakCompareAndSet(int expect, int update) | weakCompareAndSet沒法保證除操做目標外的其餘變量的執行順序( 編譯器和處理器爲了優化程序性能而對指令序列進行從新排序 ),同時也沒法保證這些變量的可見性。 |
與AtomicInteger相似的原子類還有AtomicBoolean和AtomicLong,底層都是經過Unsafe類作CAS操做,來原子的更新狀態值。能夠參考Oracle官方文檔:https://docs.oracle.com/javas...,再也不贅述。