一、数组类型的原子类 原子数组类型,这个其实和AtomicInteger
等类似,只不过在修改时需要指明数组下标。
CAS是按照==
来根据地址进行比较。数组比较地址,肯定是不行的,只能比较下标元素。而比较下标元素,就和元素的类型有关系了。
在java.util.concurrent.atomic
中,原子类型数组有以下四种:
类名
说明
AtomicIntegerArray
提供对int[]数组元素的原子性更新操作
AtomicLongArray
提供对long[]数组元素的原子性更新操作
AtomicReferenceArray
提供对引用类型[]
数组元素的原子性更新操作
AtomicBooleanArray
原子更新布尔类型数组的元素
使用原子的方式更新数组里的某个元素。
二、常用方法 其中AtomicIntegerArray
和AtomicLongArray
的使用方式差别不大,AtomicReferenceArray
因为他的参数为引用数组,所以跟前两个的使用方式有所不同。AtomicBooleanArray
在生产中使用的很少。
本次只对AtomicLongArray
和AtomicReferenceArray
方法进行详细的介绍。
2.1 AtomicLongArray介绍 构造方法
方法名
说明
AtomicLongArray(int length)
创建给定长度的新 AtomicLongArray
AtomicLongArray(long[] array)
创建与给定数组具有相同长度的新 AtomicLongArray
,并从给定数组复制其所有元素
源码
1 2 3 4 5 6 7 8 9 10 public AtomicLongArray (int length) { array = new long [length]; }public AtomicLongArray (long [] array) { this .array = array.clone(); }
方法
方法
说明
long getAndIncrement(int i)
以原子方式将索引 i
的元素自增 1
,并返回旧值
long incrementAndGet(int i)
以原子方式将索引 i
的元素自增 1
,并返回减少之后的值
long getAndDecrement(int i)
以原子形式将索引i
处的元素原子自减1
,并返回旧值
long decrementAndGet(int i)
以原子形式将索引i
处的元素原子自减1
,并返回减少之后的值
long addAndGet(int i, long delta)
以原子形式将给定元素与数组中索引i
的元素相加
long getAndSet(int i, long newValue)
将地位i
处的元素原子设置为给定值,并返回旧值
long getAndIncrement(int i)
原子的将给定的值增加到索引i
的元素
long get(int i)
获取位置 i
的当前值
void lazySet(int i, long newValue)
最终将位置 i
的元素设置为给定值
int length()
返回数组的长度
void set(int i, long newValue)
将位置 i
的元素设置为给定值
boolean compareAndSet(int i,int expect,int update)
如果当前值 ==
预期值,则以原子方式将该值设置为给定的更新值。
boolean weakCompareAndSet(int i, int expect, long update)
如果当前值 ==
预期值,则以原子方式将位置 i
的元素设置为给定的更新值
long getAndUpdate(int i, LongUnaryOperator updateFunction)
应用将给定函数利用以后值和给定值的原子更新以后值,返回旧值
long updateAndGet(int i, LongUnaryOperator updateFunction)
应用将给定函数利用以后值和给定值的原子更新以后值,返回新值
方法示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 import java.util.concurrent.atomic.AtomicLongArray;import java.util.function.LongBinaryOperator;import java.util.function.LongUnaryOperator;public class AtomicExample { private static AtomicLongArray arr = new AtomicLongArray (5 ); private static LongUnaryOperator longUnaryOperator = new LongUnaryOperator () { @Override public long applyAsLong (long operand) { return operand + 10 ; } }; private static LongBinaryOperator accumulatorFunction = new LongBinaryOperator () { @Override public long applyAsLong (long left, long right) { return left + right; } }; public static void main (String[] args) { for (int i = 0 ; i < arr.length(); i++) { System.out.println("i-" + i + "=" + arr.get(i)); } System.out.println("索引 0 incrementAndGet=" + arr.getAndIncrement(0 )); System.out.println("索引 0 incrementAndGet=" + arr.incrementAndGet(0 )); System.out.println("索引 0 incrementAndGet=" + arr.getAndDecrement(0 )); System.out.println("索引 0 incrementAndGet=" + arr.decrementAndGet(0 )); System.out.println("索引 0 addAndGet=" + arr.addAndGet(0 , 100 )); System.out.println("索引 0 get=" + arr.get(0 )); System.out.println("*********** JDK 1.8 ***********" ); System.out.println("索引 0 getAndUpdate=" + arr.updateAndGet(0 , longUnaryOperator)); System.out.println("索引 1 getAndUpdate=" + arr.updateAndGet(1 , longUnaryOperator)); System.out.println("索引 1 accumulateAndGet=" + arr.accumulateAndGet(1 , 10 , accumulatorFunction)); } }
运行结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 i-0=0 i-1=0 i-2=0 i-3=0 i-4=0 索引 0 incrementAndGet=0 索引 0 incrementAndGet=2 索引 0 incrementAndGet=2 索引 0 incrementAndGet=0 索引 0 addAndGet=100 索引 0 get=100**** **** *** JDK 1.8 ** **** **** * 索引 0 getAndUpdate=110 索引 1 getAndUpdate=10 索引 1 accumulateAndGet=20
2.2 AtomicReferenceArray介绍 构造方法
方法名
说明
AtomicReferenceArray(E[] array)
创建与给定数组具有相同长度的新 AtomicReferenceArray
,并从给定数组复制其所有元素
AtomicReferenceArray(int length)
创建给定长度的新 AtomicReferenceArray
源码
1 2 3 4 5 6 7 8 public AtomicReferenceArray (int length) { array = new Object [length]; }public AtomicReferenceArray (E[] array) { this .array = Arrays.copyOf(array, array.length, Object[].class); }
方法
方法
说明
boolean compareAndSet(int i, E expect, E update)
如果当前值 ==
预期值,则以原子方式将位置 i 的元素设置为给定的更新值
E get(int i)
获取位置 i
的当前值
E getAndSet(int i, E newValue)
以原子方式将位置 i
的元素设置为给定值,并返回旧值
void lazySet(int i, E newValue)
最终将位置 i
的元素设置为给定值
int length()
返回该数组的长度
void set(int i, E newValue)
将位置 i
的元素设置为给定值
boolean weakCompareAndSet(int i, E expect, E update)
如果当前值 ==
预期值,则以原子方式将位置 i
的元素设置为给定的更新值
方法示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import java.util.concurrent.atomic.AtomicReferenceArray;public class AtomicReferenceArrayTest { public static void main (String[] args) { Long[] l = new Long [4 ]; String[] s = new String [4 ]; int [] i = new int [4 ]; Integer[] in = new Integer [4 ]; AtomicReferenceArray atomicReferenceArray = new AtomicReferenceArray (l); System.out.println(atomicReferenceArray.length()); System.out.println(atomicReferenceArray.get(2 )); AtomicReferenceArray atomic = new AtomicReferenceArray (4 ); atomic.set(0 ,12 ); atomic.set(2 ,"Leefs" ); atomic.set(3 ,i); System.out.println(atomic.toString()); } }
运行结果
1 2 3 4 null [12 , null , Leefs, [I@ 63947c6b]
说明 :
当使用AtomicReferenceArray(E[] array)
这个构造方法传入一个数组对象时,该数组对象必须是引用类型,int[]不可以,但是Integer[]的可以。
当使用AtomicReferenceArray(int length)
这个构造函数的时候,只要为他指定了数组大小之后,为数组的每一位设置什么值是没有要求的,类似于Map的形式。
三、原子性测试
创建10个线程,每个线程分别对数组操作(自增)10000次(采用了函数式编程)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 private static <T> void demo ( Supplier<T> arraySupplier, Function<T,Integer> lengthFun, BiConsumer<T,Integer> putConsumer, Consumer<T> printConsumer) { List<Thread> threadList = new ArrayList <>(); T array = arraySupplier.get(); int length = lengthFun.apply(array); for (int i = 0 ; i < length; i++) { threadList.add(new Thread (() -> { for (int j = 0 ; j < 10000 ; j++) { putConsumer.accept(array, j%length); } })); } threadList.forEach(t -> t.start()); threadList.forEach(t -> { try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } }); printConsumer.accept(array); }
不安全的数组
1 2 3 4 5 6 demo( ()->new int [10 ], (array)->array.length, (array, index) -> array[index]++, array-> System.out.println(Arrays.toString(array)) );
运行结果
1 [6794 , 6687 , 6664 , 6587 , 6576 , 6491 , 6480 , 6530 , 6536 , 6740 ]
安全的数组
1 2 3 4 5 6 demo( ()->new AtomicIntegerArray (10 ), (arr)-> arr.length(), (arr,index) -> arr.getAndIncrement(index), (arr)->System.out.println(arr) );
运行结果
1 [10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000 ]