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

 

posted @ 2021-08-25 16:34  姚春辉  阅读(173)  评论(0编辑  收藏  举报