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: 10
System.out.println(arr.get(0)); // result: 5
int i2 = arr.updateAndGet(0, operand -> operand * 3);
System.out.println(i2); // result: 15
System.out.println(arr.get(0)); // result: 15
//lambda表達式中參數left表示數組下標爲0的元素當前值,right表示第二個參數2
int i3 = arr.getAndAccumulate(0, 2, (left, right) -> left * right);
System.out.println(i3); // result: 15
System.out.println(arr.get(0)); // result: 30
int i4 = arr.accumulateAndGet(0, 2, (left, right) -> left * right);
System.out.println(i4); // result: 60
System.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)