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