2019獨角獸企業重金招聘Python工程師標準>>>
AtomicIntegerArray
對int數組中元素的操作不是原子性的,所以存在并發操作時,我們應該使用AtomicIntegerArray類來代替int數組。
下面是驗證演示代碼:
public class AtomicIntegerArrayDemo {static AtomicIntegerArray aiArr = new AtomicIntegerArray(5);static int[] intArr = new int[5];/*** 并發測試,對數組的每個元素進行遞增操作*/public static void main(String[] args) throws InterruptedException {ExecutorService threadPool = Executors.newCachedThreadPool();for(int t = 0; t < 5; t++) {threadPool.execute(() -> {for (int i = 0; i < 1000000; i++) {aiArr.getAndIncrement(i % 5);}});threadPool.execute(() -> {for (int i = 0; i < 1000000; i++) {intArr[i % 5]++;}});}threadPool.shutdown();boolean b = threadPool.awaitTermination(5, TimeUnit.SECONDS);if(b) {System.out.println("aiArr:" + aiArr.toString());System.out.println("intArr:" + Arrays.toString(intArr));}else{System.out.println("time out.");}}
}
運行結果:
D:\Java\jdk1.8.0_171\bin\java.exe "-javaagent:D:\JetBrains\IntelliJ IDEA
aiArr:[1000000, 1000000, 1000000, 1000000, 1000000]
intArr:[892703, 891096, 892369, 892372, 893754]
AtomicIntegerArray的常用方法:
//獲取數組長度
int length()//獲取數組中下標為i的元素的值
int get(int i)//設置數組中下標為i的元素的值為newValue
void set(int i, int newValue)//設置數組中下標為i的元素的值為newValue,返回以前的值
int getAndSet(int i, int newValue)//如果數組中下標為i的元素的值等于入參expect,則把值修改為update,并返回ture,如果不等則不修改并返回false
boolean compareAndSet(int i, int expect, int update)// arr[i]++
int getAndIncrement(int i)// arr[i]--
int getAndDecrement(int i)// ++arr[i]
int incrementAndGet(int i)// --arr[i]int decrementAndGet(int i)//數組中下標為i的元素的值加上delta,返回以前的值
int getAndAdd(int i, int delta)//數組中下標為i的元素的值加上delta,返回新的值
int addAndGet(int i, int delta)//1.8新增方法,更新當前值,返回以前的值
int getAndUpdate(int i, IntUnaryOperator updateFunction)// 1.8新增方法,更新當前值,返回更新后的值
int updateAndGet(int i, IntUnaryOperator updateFunction)// 1.8新增方法,更新當前值,返回以前的值
int getAndAccumulate(int i, int x, IntBinaryOperator accumulatorFunction)// 1.8新增方法,更新當前值,返回更新后的值
int accumulateAndGet(int i, int x, IntBinaryOperator accumulatorFunction)
*** 1.8新增方法演示*/
@Test
public void atomicIntegerArrayMethodTest(){AtomicIntegerArray arr = new AtomicIntegerArray(2);arr.set(0, 10);//lambda表達式中參數operand表示數組下標為0的元素當前值int i1 = arr.getAndUpdate(0, operand -> operand / 2);System.out.println(i1); // result: 10System.out.println(arr.get(0)); // result: 5int i2 = arr.updateAndGet(0, operand -> operand * 3);System.out.println(i2); // result: 15System.out.println(arr.get(0)); // result: 15//lambda表達式中參數left表示數組下標為0的元素當前值,right表示第二個參數2int i3 = arr.getAndAccumulate(0, 2, (left, right) -> left * right);System.out.println(i3); // result: 15System.out.println(arr.get(0)); // result: 30int i4 = arr.accumulateAndGet(0, 2, (left, right) -> left * right);System.out.println(i4); // result: 60System.out.println(arr.get(0)); // result: 60
}
AtomicIntegerFieldUpdater
AtomicIntegerFieldUpdater是用來原子的操作對象中int類型字段的。 下面是驗證演示代碼:
public class AtomicIntegerFieldUpdaterDemo {/*** 并發測試,對Counter的index字段進行遞增操作*/public static void main(String[] args) throws InterruptedException {Counter counter1 = new Counter();AtomicIntegerFieldUpdater<Counter> counterIndexFieldUpdater = AtomicIntegerFieldUpdater.newUpdater(Counter.class, "index");Counter counter2 = new Counter();ExecutorService threadPool = Executors.newCachedThreadPool();for(int t = 0; t < 5; t++) {threadPool.execute(() -> {for (int i = 0; i < 1000000; i++) {counter1.index++;}});threadPool.execute(() -> {for (int i = 0; i < 1000000; i++) {counterIndexFieldUpdater.getAndIncrement(counter2);}});}threadPool.shutdown();boolean b = threadPool.awaitTermination(5, TimeUnit.SECONDS);if(b) {System.out.println("counter1.index:" + counter1.index);System.out.println("counter2.index:" + counterIndexFieldUpdater.getAndIncrement(counter2));}else{System.out.println("time out.");}}
}class Counter{/** 必須是volatile修飾的 */public volatile int index = 0;
}
運行結果:
D:\Java\jdk1.8.0_171\bin\java.exe "-javaagent:D:\JetBrains\IntelliJ IDEA
counter1.index:4192522
counter2.index:5000000
值得注意的是,使用的時候注意如下幾點:
- 字段必須是volatile類型的,在線程之間共享變量時保證立即可見
- 字段的描述類型(修飾符public/protected/default/private)是與調用者與操作對象字段的關系一致。也就是說調用者能夠直接操作對象字段,那么就可以反射進行原子操作。
- 對于父類的字段,子類是不能直接操作的,盡管子類可以訪問父類的字段。
- 只能是實例變量,不能是類變量,也就是說不能加static關鍵字。
- 只能是可修改變量,不能使final變量,因為final的語義就是不可修改。
- 對于AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long類型的字段,不能修改其包裝類型(Integer/Long)。如果要修改包裝類型就需要使用AtomicReferenceFieldUpdater。
參考:Java并發學習(九)-AtomicIntegerFieldUpdater字段原子更新類
AtomicIntegerArray的常用方法:
//創建AtomicIntegerFieldUpdater對象,tclass為需要操作對象的類型,fieldName為需要操作字段名稱
static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName)//如果obj中指定字段的值等于expect,則把該字段的值設為update
boolean compareAndSet(T obj, int expect, int update) //把obj中指定字段的值設置為newValue
void set(T obj, int newValue);//返回obj中指定字段的值
int get(T obj);//把obj中指定字段的值設置為newValue,返回以前的值
int getAndSet(T obj, int newValue)//i++
int getAndIncrement(T obj)//++i
int incrementAndGet(T obj)//i--
int getAndDecrement(T obj)
//--i
decrementAndGet(T obj)//把obj中指定字段的值加上delta,返回以前的值
int getAndAdd(T obj, int delta)//把obj中指定字段的值加上delta,返回更新后的值
int addAndGet(T obj, int delta)//1.8新增方法,更obj中指定字段的值,返回以前的值
int getAndUpdate(T obj, IntUnaryOperator updateFunction)//1.8新增方法,更obj中指定字段的值,返回更新后的值
int updateAndGet(T obj, IntUnaryOperator updateFunction)//1.8新增方法,更obj中指定字段的值,返回以前的值
int getAndAccumulate(T obj, int x, IntBinaryOperator accumulatorFunction)//1.8新增方法,更obj中指定字段的值,返回更新后的值
int accumulateAndGet(T obj, int x, IntBinaryOperator accumulatorFunction)