Java併發24:Atomic系列-原子型別陣列AtomicXxxxArray學習筆記
阿新 • • 發佈:2021-08-25
1.原子型別陣列
在java.util.concurrent.atomic中,原子型別陣列有以下三種:
- AtomicLongArray:提供對int[]陣列元素的原子性更新操作。
- AtomicIntegerArray:提供對long[]陣列元素的原子性更新操作。
- AtomicReferenceArray:提供對引用型別[]陣列元素的原子性更新操作。
2.內部實現淺談
檢視部分原子型別陣列的原始碼:
/** * An {@code int} array in which elements may be updated atomically. * See the {@link java.util.concurrent.atomic} package * specification for description of the properties of atomic * variables. *@since 1.5 * @author Doug Lea */ public class AtomicIntegerArray implements java.io.Serializable { private static final long serialVersionUID = 2862133569453604235L; private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final int base = unsafe.arrayBaseOffset(int[].class); private static final int shift; private final int[] array; static { int scale = unsafe.arrayIndexScale(int[].class); if ((scale & (scale - 1)) != 0) throw new Error("data type scale not a power of two"); shift = 31 - Integer.numberOfLeadingZeros(scale); }//... /** * Sets the element at position {@code i} to the given value. * * @param i the index * @param newValue the new value */ public final void set(int i, int newValue) { unsafe.putIntVolatile(array, checkedByteOffset(i), newValue); } }
從上面的原始碼可知,原子型別在內部通過Unsafe類的native方法保證操作的原子性。
3.原子型別陣列的通用方法
首先學習上述三種原子型別陣列的通用方法,這些方法如下:
- 構造器:分為初始長度構造器和初始陣列構造器,不提供無參構造器。
- get(index):取值,具有原子性和可見性。
- set(index):賦值,具有原子性和可見性。
- lazySet(index,newValue):賦值,具有原子性,不具備可見性。
- getAndSet(index,newValue):賦值並返回舊值,具有原子性和可見性。
- compareAndSet(index,expect,newValue):如果當前是期望值則賦值並返回賦值成功與否,具有原子性和可見性。
- weakCompareAndSet(index,expect,newValuee):與compareAndSet(index,expect,newValue)類似。
原子型別陣列的通用方法與普通原子型別的通用方法類似,唯一的區別在於多了一個引數:index(陣列元素下標)
例項程式碼:
//構造器 LOGGER.info("===========原子陣列構造器"); //陣列構造器 AtomicIntegerArray aIntArray = new AtomicIntegerArray(new int[]{1,2,3,4,5}); AtomicReferenceArray aStrArray = new AtomicReferenceArray<>(new String []{"David","Jone","Gray"}); LOGGER.info("AtomicIntegerArray(int[]):" + aIntArray.toString()); LOGGER.info("AtomicReferenceArray(String[]):" + aStrArray.toString()); //長度構造器 LOGGER.info("AtomicIntegerArray(length):" + new AtomicIntegerArray(10).toString()); LOGGER.info("AtomicIntegerReference(length):" + new AtomicReferenceArray<String >(10).toString() + "\n"); //通用方法 LOGGER.info("===========原子陣列通用方法:get/set/lazySet/getAndSet/CompareAndSet"); //get(index) LOGGER.info("get(index):獲取第i個元素----" + aStrArray.get(2).toString()); //set(index,newValue) aStrArray.set(0,"Dock"); LOGGER.info("set(index,newValue):設定第i個元素的值----" + aStrArray.get(0).toString()); //lazySet(index,newValue) aStrArray.lazySet(0,"Green"); LOGGER.info("lazySet(index,newValue):設定第i個元素的值(無可見性)----" + aStrArray.get(0).toString()); //getAndSet(index,newValue) LOGGER.info("getAndSet(index,newValue):設定第i個元素的值,並返回此元素的舊值----" + aStrArray.getAndSet(0,"Merlin")); //compareAndSet(index,expect,newValue) LOGGER.info("compareAndSet(index,expect,newValue):如果第i個元素的值是期望的值,則設定新值,並返回執行結果----" + aStrArray.compareAndSet(0,"Merlin","Love")); //length LOGGER.info("length():陣列長度----" + aStrArray.length()); LOGGER.info("weakCompareAndSet(index,expect,newValue)的實現的效果與compareAndSet(index,expect,newValue)一致,但可能失敗[其實不會失敗,因為其原始碼與後者一致。]\n");
執行結果:
2018-03-25 15:42:55 INFO AtomicArrayDemo:21 - ===========原子陣列構造器 2018-03-25 15:42:56 INFO AtomicArrayDemo:25 - AtomicIntegerArray(int[]):[1, 2, 3, 4, 5] 2018-03-25 15:42:56 INFO AtomicArrayDemo:26 - AtomicReferenceArray(String[]):[David, Jone, Gray] 2018-03-25 15:42:56 INFO AtomicArrayDemo:28 - AtomicIntegerArray(length):[0, 0, 0, 0, 0, 0, 0, 0, 0, 0] 2018-03-25 15:42:56 INFO AtomicArrayDemo:29 - AtomicIntegerReference(length):[null, null, null, null, null, null, null, null, null, null] 2018-03-25 15:42:56 INFO AtomicArrayDemo:32 - ===========原子陣列通用方法:get/set/lazySet/getAndSet/CompareAndSet 2018-03-25 15:42:56 INFO AtomicArrayDemo:34 - get(index):獲取第i個元素----Gray 2018-03-25 15:42:56 INFO AtomicArrayDemo:37 - set(index,newValue):設定第i個元素的值----Dock 2018-03-25 15:42:56 INFO AtomicArrayDemo:40 - lazySet(index,newValue):設定第i個元素的值(無可見性)----Green 2018-03-25 15:42:56 INFO AtomicArrayDemo:42 - getAndSet(index,newValue):設定第i個元素的值,並返回此元素的舊值----Green 2018-03-25 15:42:56 INFO AtomicArrayDemo:44 - compareAndSet(index,expect,newValue):如果第i個元素的值是期望的值,則設定新值,並返回執行結果----true 2018-03-25 15:42:56 INFO AtomicArrayDemo:46 - length():陣列長度----3 2018-03-25 15:42:56 INFO AtomicArrayDemo:47 - weakCompareAndSet(index,expect,newValue)的實現的效果與compareAndSet(index,expect,newValue)一致,但可能失敗[其實不會失敗,因為其原始碼與後者一致。]
4.AtomicIntegerArray和AtomicLongArray的獨有方法
然後學習AtomicIntegerArray和AtomicLongArray獨有的一些方法,這些方法如下:
- getAndAdd(index,delta):增量計算並返回舊值,具有原子性和可見性。
- addAndGet(index,delta):增量計算並返回新值,具有原子性和可見性。
- getAndIncrement(index):自增並返回舊值,類似i ++,具有原子性和可見性。
- incrementAndGet(index):自增並返回新值,類似++ i,具有原子性和可見性。
- getAndDecrement(index):自減並返回舊值,類似i --,具有原子性和可見性。
- decrementAndGet(index):自減並返回新值,類似-- i,具有原子性和可見性。
AtomicIntegerArray和AtomicLongArray的獨有方法與AtomicInteger和AtomicLong的獨有方法類似,唯一的區別在於多了一個引數:index(陣列元素下標)
例項程式碼:
//AtomicIntegerArray和AtomicLongArray的獨有方法:getAndAdd/addAndGet/i++/i--/++i/--i LOGGER.info("===========AtomicIntegerArray和AtomicLongArray的獨有方法:getAndAdd/addAndGet/i++/i--/++i/--i"); //getAndAdd(index,newValue)和addAndGet(index,newValue) aIntArray.set(2,0); LOGGER.info("i = 2,value = " + aIntArray.get(2)); LOGGER.info("getAndAdd(index,newValue):增量計算,返回舊值----" + aIntArray.getAndAdd(2,2)); aIntArray.set(2,0); LOGGER.info("addAndGet(index,newValue):增量計算,返回新值----" + aIntArray.addAndGet(2,2)); //getAndIncrement(index)和incrementAndGet(index) aIntArray.set(2,0); LOGGER.info("i = 2,value = " + aIntArray.get(2)); LOGGER.info("getAndIncrement(index):自增計算,返回舊值----" + aIntArray.getAndIncrement(2)); aIntArray.set(2,0); LOGGER.info("incrementAndGet(index):自增計算,返回新值----" + aIntArray.incrementAndGet(2)); //getAndDecrement(index)decrementAndGet(index) aIntArray.set(2,0); LOGGER.info("i = 2,value = " + aIntArray.get(2)); LOGGER.info("getAndDecrement(index):自減計算,返回舊值----" + aIntArray.getAndDecrement(2)); aIntArray.set(2,0); LOGGER.info("decrementAndGet(index):自減計算,返回新值----" + aIntArray.decrementAndGet(2));
執行結果:
2018-03-25 15:42:56 INFO AtomicArrayDemo:50 - ===========AtomicIntegerArray和AtomicLongArray的獨有方法:getAndAdd/addAndGet/i++/i--/++i/--i
2018-03-25 15:42:56 INFO AtomicArrayDemo:53 - i = 2,value = 0
2018-03-25 15:42:56 INFO AtomicArrayDemo:54 - getAndAdd(index,newValue):增量計算,返回舊值----0
2018-03-25 15:42:56 INFO AtomicArrayDemo:56 - addAndGet(index,newValue):增量計算,返回新值----2
2018-03-25 15:42:56 INFO AtomicArrayDemo:59 - i = 2,value = 0
2018-03-25 15:42:56 INFO AtomicArrayDemo:60 - getAndIncrement(index):自增計算,返回舊值----0
2018-03-25 15:42:56 INFO AtomicArrayDemo:62 - incrementAndGet(index):自增計算,返回新值----1
2018-03-25 15:42:56 INFO AtomicArrayDemo:65 - i = 2,value = 0
2018-03-25 15:42:56 INFO AtomicArrayDemo:66 - getAndDecrement(index):自減計算,返回舊值----0
2018-03-25 15:42:56 INFO AtomicArrayDemo:68 - decrementAndGet(index):自減計算,返回新值-----1