您好,登錄后才能下訂單哦!
這篇文章主要介紹“什么是Java原子類”,在日常操作中,相信很多人在什么是Java原子類問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”什么是Java原子類”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
Java中的原子類是java.util.concurrent.atomic包下的對象,他們之所以有原子性的共性,都來源于CAS,可見CAS的重要性。對于原子類變量的操作是不會存在并發性問題的,不需要使用同步手段進行并發控制。它底層自身的實現即可保證變量的可見性以及操作的原子性,一般我們可以使用AtomicInteger,AtomicLong等實現計數器等功能,利用AtomicBoolean實現標志位等功能。
原子類是JDK5提供的,當時只有12個原子類,發展到JDK8時,又多出了4個原子類,如下圖2-25所示,紅色框內為JDK8新增加的。
圖2-25 Java16個原子類
下面我們來對這些原子類進行分類講解。
2.10.1原子更新基本類型
l AtomicBoolean: 原子更新布爾類型。
l AtomicInteger: 原子更新整型。
l AtomicLong: 原子更新長整型。
我們以AtomicInteger為例,AtomicIngeter的常用方法如下:
n int addAndGet(int delta): 以原子的方式將參數與實例中的值相加,并返回結果。
n boolean compareAndSet(int expect, int update): 如果輸入的值等于預期值,則以原子方式將該值設置為輸入的值。
n int getAndIncrement(): 以原子的方式將當前值加1,然后返回自增前的值,也就是舊值。此方法也是比較常用的方法,可以用來做計數器。
n void lazySet(int newValue): 最終會設置成newValue,使用lazySet設置值后,可能導致其他線程在之后的一小段時間內還是可以讀到舊的值。
n int getAndSet(int newValue): 以原子的方式設置為newValue,并返回舊值。
n int incrementAndGet(): 和getAndIncrement一樣,他返回的是自增后的值。
記得在講解CAS應用的代碼案例中,使用過原子自增的方法,下面我們看看getAndIncrement() 是如何實現原子操作的,請看2-45示例代碼中AtomicInteger部分源碼。
代碼清單2-45 AtomicInteger.java
public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 1); } 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; }
我們取得了舊值,然后把要加的數傳過去,調用getAndAddInt () 進行原子更新操作,實際最核心的方法是 compareAndSwapInt(),使用CAS進行更新。我們Unsafe只提供了3中CAS操作,另外注意,AtomicBoolean 是把Boolean轉成整型,在使用 compareAndSwapInt 進行操作的。在atomic包里的對象基本都是使用Unsafe提供的3中CAS操作的方法實現的,請看Unsafe源碼,如代碼清單2-46所示。
代碼清單2-46 Unsafe.java
/** * 如果當前數值是var4,則原子的將java變量更新成var5或var6 * @return 如果更新成功返回true */ public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5); public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5); public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
2.10.2原子更新數組
l AtomicIntegerArray: 原子更新整型數組里的元素。
l AtomicLongArray: 原子更新長整型數組里的元素。
l AtomicReferenceArray: 原子更新引用類型數組里的元素。
這三個類的最常用的方法是如下兩個方法:
n get(int index):獲取索引為index的元素值。
n compareAndSet(int i, int expect, int update): 如果當前值等于預期值,則以原子方式將數組位置 i 的元素設置為update值。
2.10.3原子更新引用類型
l AtomicReference: 原子更新引用類型。
l AtomicReferenceFieldUpdater: 原子更新引用類型的字段。
l AtomicMarkableReferce: 原子更新帶有標記位的引用類型,可以使用構造方法更新一個布爾類型的標記位和引用類型。
這三個類提供的方法都差不多,首先構造一個引用對象,然后把引用對象set進Atomic類,然后調用compareAndSet等一些方法去進行原子操作,原理都是基于Unsafe實現,但AtomicReferenceFieldUpdater略有不同,更新的字段必須用volatile修飾。下面我們使用原子引用類型寫一個簡單的Demo,請看示例代碼2-47所示
代碼清單2-47 AtomicReferenceDemo.java
public class AtomicReferenceDemo { public static AtomicReference<User> ai = new AtomicReference<User>(); public static void main(String[] args) { User u1 = new User("pangHu", 18); ai.set(u1); User u2 = new User("pangPang", 15); ai.compareAndSet(u1, u2); System.out.println(ai.get().getAge() + ai.get().getName()); } static class User { private String name; private int age; //省略getter、settrt } }
輸出結果。
15pangPang
2.10.4原子更新字段類
如果需要原子的更新類里某個字段時,需要用到原子更新字段類,Atomic包提供了3個類進行原子字段更新:
l AtomicIntegerFieldUpdater: 原子更新整型的字段的更新器。
l AtomicLongFieldUpdater: 原子更新長整型字段的更新器。
l AtomicStampedFieldUpdater: 原子更新帶有版本號的引用類型。該方法比較重要,他和引用類型加上一個整數值,可以控制數據的版本號,這樣就可以解決CAS更新時可能出現的ABA問題。和引用類型一樣更新類的字段必須使用 public volatile 修飾。
2.10.5 JDK8新增原子類簡介
l DoubleAccumulator
l LongAccumulator
l DoubleAdder
l LongAdder
下面以 LongAdder 為例介紹一下,并列出使用注意事項。
這些類對應把 AtomicLong 等類的改進。比如 LongAccumulator 與 LongAdder 在高并發環境下比 AtomicLong 更高效。
Atomic、Adder在低并發環境下,兩者性能很相似。但在高并發環境下,Adder 有著明顯更高的吞吐量,但是有著更高的空間復雜度。
LongAdder其實是LongAccumulator的一個特例,調用LongAdder相當使用下面的方式調用LongAccumulator。
sum()方法在沒有并發的情況下調用,如果在并發情況下使用會存在計數不準,下面有代碼為例。
LongAdder不可以代替AtomicLong,雖然 LongAdder的add()方法可以原子性操作,但是并沒有使用 Unsafe 的CAS算法,只是使用了CAS的思想。
LongAdder其實是LongAccumulator的一個特例,調用LongAdder相當使用下面的方式調用LongAccumulator,LongAccumulator提供了比LongAdder更強大的功能,構造函數其中accumulatorFunction一個雙目運算器接口,根據輸入的兩個參數返回一個計算值,identity則是LongAccumulator累加器的初始值。
到此,關于“什么是Java原子類”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。