AtomicIntegerArray和AtomicIntegerFieldUpdater

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

值得注意的是,使用的时候注意如下几点:

  1. 字段必须是volatile类型的,在线程之间共享变量时保证立即可见
  2. 字段的描述类型(修饰符public/protected/default/private)是与调用者与操作对象字段的关系一致。也就是说调用者能够直接操作对象字段,那么就可以反射进行原子操作。
  3. 对于父类的字段,子类是不能直接操作的,尽管子类可以访问父类的字段。
  4. 只能是实例变量,不能是类变量,也就是说不能加static关键字。
  5. 只能是可修改变量,不能使final变量,因为final的语义就是不可修改。
  6. 对于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)

猜你喜欢

转载自my.oschina.net/u/2424727/blog/1933993