java线程回调数组_Java多线程:AtomicIntegerArray 原子更新数组类

Java多线程:AtomicIntegerArray 原子更新数组类

前言

原子更新数组类顾名思义,通过原子的方式更新数组里的某个元素,Atomic包提供了以下三个类:

AtomicIntegerArray:原子更新整型数组里的元素。

AtomicLongArray:原子更新长整型数组里的元素。

AtomicReferenceArray:原子更新引用类型数组里的元素。

以上3个类提供的方法几乎一模一样,以 AtomicIntegerArray 类为例,它主要是提供原子的方式更新数组里的整型,其常用方法如下:

// 创建给定长度的新 AtomicIntegerArray。

AtomicIntegerArray(int length)

// 创建与给定数组具有相同长度的新 AtomicIntegerArray,并从给定数组复制其所有元素。

AtomicIntegerArray(int[] array)

/**

* 返回值与函数名字相关,比如get在前就返回原始值再进行加减设置等操作,get在后则先进行操作再返回更新后的值

* */

// 以原子方式将给定值添加到索引 i (从0开始)的元素。

int addAndGet(int i, int delta)

// 如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。

boolean compareAndSet(int i, int expect, int update)

// 以原子方式将索引 i 的元素减1。

int decrementAndGet(int i)

// 获取位置 i 的当前值。

int get(int i)

// 以原子方式将给定值与索引 i 的元素相加。

int getAndAdd(int i, int delta)

// 以原子方式将索引 i 的元素减 1。

int getAndDecrement(int i)

// 以原子方式将索引 i 的元素加 1。

int getAndIncrement(int i)

// 以原子方式将位置 i 的元素设置为给定值,并返回旧值。

int getAndSet(int i, int newValue)

// 以原子方式将索引 i 的元素加1。

int incrementAndGet(int i)

// 最终将位置 i 的元素设置为给定值。

void lazySet(int i, int newValue)

// 返回该数组的长度。

int length()

// 将位置 i 的元素设置为给定值。

void set(int i, int newValue)

// 返回数组当前值的字符串表示形式。

String toString()

// 如果位置 i 的元素当前值 == 预期值,则以原子方式将该值设置为给定的更新值。

boolean weakCompareAndSet(int i, int expect, int update)

AtomicIntegerArray 的使用例子:

1 import java.util.concurrent.atomic.AtomicIntegerArray;

2

3 public class Demo

4 {

5 static AtomicIntegerArray atom = new AtomicIntegerArray(a);

6 public static void main(String[] agrs)

7 {

8 int[] a = {1, 2, 3, 4, 5};

9

10 System.out.println("原始数组:" + atom);

11

12 System.out.println("调用addAndGet(1, 9)方法返回值:" + atom.addAndGet(1, 9));

13 System.out.println("调用后数组为:" + atom);

14

15 System.out.println("调用getAndDecrement(2)方法返回值:" + atom.getAndDecrement(2));

16 System.out.println("调用后数组为:" + atom);

17

18 System.out.println("调用incrementAndGet(3)方法返回值:" + atom.incrementAndGet(3));

19 System.out.println("调用后数组为:" + atom);

20

21 System.out.println("调用compareAndSet(4, 5, 100)方法返回值:" + atom.compareAndSet(4, 5, 100));

22 System.out.println("调用后数组为:" + atom);

23 }

24 }

打印结果为:

原始数组:[1, 2, 3, 4, 5]

调用addAndGet(1, 9)方法返回值:11

调用后数组为:[1, 11, 3, 4, 5]

调用getAndDecrement(2)方法返回值:3

调用后数组为:[1, 11, 2, 4, 5]

调用incrementAndGet(3)方法返回值:5

调用后数组为:[1, 11, 2, 5, 5]

调用compareAndSet(4, 5, 100)方法返回值:tr

调用后数组为:[1, 11, 2, 5, 100]

AtomicIntegerArray类需要注意的是,数组value通过构造方法传递进去,然后AtomicIntegerArray会将当前数组复制一份,所以当AtomicIntegerArray对内部的数组元素进行修改时,不会影响到传入的数组。

源码如下:

1 /**

2 * Creates a new AtomicLongArray of the given length, with all

3 * elements initially zero.

4 *

5 * @param length the length of the array

6 */

7 public AtomicLongArray(int length) {

8 array = new long[length];

9 }

10

11 /**

12 * Creates a new AtomicLongArray with the same length as, and

13 * all elements copied from, the given array.

14 *

15 * @param array the array to copy elements from

16 * @throws NullPointerException if array is null

17 */

18 public AtomicLongArray(long[] array) {

19 // Visibility guaranteed by final field guarantees

20 this.array = array.clone();

21 }

那这个类是如何做到原子性操作的呢?我们可以通过底层代码来看一下

下面仅以incrementAndGet()为例,对AtomicInteger的原理进行说明。

1 public final int incrementAndGet(int i) {

2 return addAndGet(i, 1);

3 }

4 public int addAndGet(int i, int delta) {

5 // 检查数组是否越界

6 int offset = checkedByteOffset(i);

7 while (true) {

8 // 获取int型数组的索引 offset 的原始值

9 int current = getRaw(offset);

10 // 修改int型值

11 int next = current + delta;

12 // 通过CAS更新int型数组的索引 offset的值。

13 if (compareAndSetRaw(offset, current, next))

14 return next;

15 }

16 }

incrementAndGet() 其实调用了 addAndGet() 方法,指定相加的数为1。在循环中,获取下表为 i 的元素的当前值,通过compareAndSet() 方法与下标为 i的元素的原始值进行对比,如果相同则进行更新,否则循环再执行一遍。

其中 getRaw() 和compareAndSet()方法都是调用了 Unsafe 类中的方法

private int getRaw(int offset) {

return unsafe.getIntVolatile(array, offset);

}

private boolean compareAndSetRaw(int offset, int expect, int update) {

return unsafe.compareAndSwapInt(array, offset, expect, update);

}

private static final Unsafe unsafe = Unsafe.getUnsafe();

Unsafe 这个类提供了硬件级别的原子操作,因为Java不能直接访问操作系统的底层,而只能通过本地方法(native)来访问,Unsafe类中就提供了一些这样的本地方法。这些方法可以直接定位对象某字段的内存位置,也可对它进行修改。上面两个方法就是这样的。

原文链接:https://www.cnblogs.com/2015110615L/p/6748999.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值