1. 程式人生 > 其它 >Java併發24:Atomic系列-原子型別陣列AtomicXxxxArray學習筆記

Java併發24:Atomic系列-原子型別陣列AtomicXxxxArray學習筆記

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