Java中的原子類AtomicInteger使用詳解
原子操作
原子操作是指不會被線程調(diào)度機(jī)制打斷的操作,這種操作一旦開始,就一直運(yùn)行到結(jié)束,中間不會有任何線程上下文切換。
原子操作可以是一個步驟,也可以是多個操作步驟,但是其順序不可以被打亂,也不可以被切割而只執(zhí)行其中的一部分,將整個操作視作一個整體是原子性的核心特征。
原子類
在Java中提供了很多原子類,主要把這些原子類分成以下幾大類
原子更新基本類型或引用類型
- AtomicBoolean
- 原子更新布爾類型,內(nèi)部使用int類型的value存儲1和0表示true和false,底層也是對int類型的原子操作。
- AtomicInteger
- 原子更新int類型。
- AtomicLong
- 原子更新long類型。
- AtomicReference
- 原子更新引用類型,通過泛型指定要操作的類。
- AtomicMarkableReference
- 原子更新引用類型,內(nèi)部使用Pair承載引用對象及是否被更新過的標(biāo)記,避免了ABA問題。
- AtomicStampedReference
- 原子更新引用類型,內(nèi)部使用Pair承載引用對象及更新的郵戳,避免了ABA問題。
原子更新數(shù)組中的元素
原子更新數(shù)組中的元素,可以更新數(shù)組中指定索引位置的元素。
- AtomicIntegerArray
原子更新int數(shù)組中的元素。 - AtomicLongArray
原子更新long數(shù)組中的元素。 - AtomicReferenceArray
原子更新object數(shù)組中的元素。
原子更新對象中的字段
原子更新對象中的字段,可以更新對象中指定字段名稱的字段。
- AtomicIntegerFieldUpdater
原子更新對象中的int類型字段。 - AtomicLongFieldUpdater
原子更新對象中的long類型字段。 - AtomicReferenceFieldUpdater
原子更新對象中的引用類型字段。
高性能原子類
高性能原子類,是Java8中增加的原子類,它們使用分段的思想,把不同線程hash到不同的段上去更新,最后再把這些段的值相加得到最終的值。
Striped64
下面四個類的父類。
- LongAccumulator
- long類型的聚合器,需要傳入一個long類型的二元操作,可以用來計算各種聚合操作,包括加乘等。
- LongAdder
- long類型聚合器,LongAccumulator的特例,只能用來計算加法,且從零開始計算。
- DoubleAccumulator
- double類型的聚合器,需要傳入一個double類型的二元操作,可以用來計算各種聚合操作,包括加乘等。
- DoubleAdder
- double類型聚合器,DoubleAccumulator的特例,只能用來計算加法,且從零開始計算。
AtomicInteger使用
import java.util.concurrent.atomic.AtomicInteger; public class AtomicIntegerDemo { public static void main(String[] args) throws InterruptedException { test1(); test2(); } private static void test1() throws InterruptedException { Counter counter = new Counter(); for (int i = 0; i < 10; i++) { new Thread(()->{ for (int j = 0; j < 1000; j++) { counter.addCount(); } }).start(); } Thread.sleep(1000); System.out.println("test1 count = " + counter.getCount()); } private static void test2() throws InterruptedException { AtomicInteger count = new AtomicInteger(); for (int i = 0; i < 10; i++) { new Thread(()->{ for (int j = 0; j < 1000; j++) { count.incrementAndGet(); } }).start(); } Thread.sleep(1000); System.out.println("test2 count = " + count.get()); } } public class Counter { private volatile static int count = 0; public void addCount(){ count++; } public int getCount(){ return count; } }
運(yùn)行以上代碼會發(fā)現(xiàn),test1的結(jié)果達(dá)不到預(yù)期的10000,而且每次的結(jié)果不可再現(xiàn)。而test2的結(jié)果每次都是10000,是確定的可再現(xiàn)的。
是因為test1中調(diào)用的Counter類的addCount方法,這個方法不是原子性的。
count++可以分解為以下幾個原子性的步驟:
1.讀取count的值
2.計算新值count+1
3.新值寫入count變量
如果步驟1、2、3中有多個線程并發(fā)執(zhí)行,那么就會出現(xiàn)兩個或多個線程并發(fā)的執(zhí)行+1操作,而我們希望的是每個線程依次執(zhí)行+1的操作。
AtomicInteger原理
AtomicInteger聲明
public class AtomicInteger extends Number implements java.io.Serializable
Unsafe類的使用
private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long valueOffset; static { try { valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } }
AtomicInteger屬性
private volatile int value;
AtomicInteger構(gòu)造器
public AtomicInteger(int initialValue) { value = initialValue; } public AtomicInteger() { }
AtomicInteger自增
public final int incrementAndGet() { return unsafe.getAndAddInt(this, valueOffset, 1) + 1; }
調(diào)用Unsafe類的方法
public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { var5 = this.getIntVolatile(var1, var2); } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }
compareAndSwapInt即CAS方式修改int值:
- 調(diào)用unsafe.getAndAddInt方法。
- unsafe.getAndAddInt方法通過自旋的方式,每次嘗試通過CAS方式對原值進(jìn)行累加。如果累加失敗,將進(jìn)入下一次循環(huán)。如果累加成功,則自選結(jié)束。
到此這篇關(guān)于Java中的原子類AtomicInteger使用詳解的文章就介紹到這了,更多相關(guān)Java原子類AtomicInteger內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Mybatis內(nèi)置參數(shù)之_parameter和_databaseId的使用
這篇文章主要介紹了Mybatis內(nèi)置參數(shù)之_parameter和_databaseId的使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12SpringAOP 構(gòu)造注入的實現(xiàn)步驟
這篇文章主要介紹了SpringAOP_構(gòu)造注入的實現(xiàn)步驟,幫助大家更好的理解和學(xué)習(xí)使用spring框架,感興趣的朋友可以了解下2021-05-05springboot集成redis實現(xiàn)簡單秒殺系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了springboot集成redis實現(xiàn)簡單秒殺系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-12-12Java中Arrays.sort自定義一維數(shù)組、二維數(shù)組的排序方式
這篇文章主要介紹了Java中Arrays.sort自定義一維數(shù)組、二維數(shù)組的排序方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08