4.4.6 数组也能无锁:AtomicIntegerArray
除了提供基本数据类型外,JDK还为我们准备了数组等复合结构。当前可用的原子数组有:AtomicIntegerArray、AtomicLongArray和AtomicReferenceArray,分别表示整数数组、long型数组和普通的对象数组。
这里以AtomicIntegerArray为例,展示原子数组的使用方式。
AtomicIntegerArray本质上是对int[]类型的封装,使用Unsafe类通过CAS的方式控制int[]在多线程下的安全性。它提供了以下几个核心API:
获得数组第i个下标的元素
public final int getint i
获得数组的长度
public final int length
将数组第i个下标设置为newValue,并返回旧的值
public final int getAndSetint i, int newValue
进行CAS操作,如果第i个下标的元素等于expect,则设置为update,设置成功返回true
public final boolean compareAndSetint i, int expect, int update
将第i个下标的元素加1
public final int getAndIncrementint i
将第i个下标的元素减1
public final int getAndDecrementint i
将第i个下标的元素增加delta(delta可以是负数)
public final int getAndAddint i, int delta
下面给出一个简单的示例,展示AtomicIntegerArray的使用:
01 public class AtomicIntegerArrayDemo {
02 static AtomicIntegerArray arr = new AtomicIntegerArray10;
03 public static class AddThread implements Runnable{
04 public void run{
05 forint k=0;k10000;k
06 arr.getAndIncrementk%arr.length;
07 }
08 }
09 public static void mainString[] args throws InterruptedException {
10 Thread[] ts=new Thread[10];
11 forint k=0;k10;k {
12 ts[k]=new Threadnew AddThread;
13 }
14 forint k=0;k10;k {ts[k].start;}
15 forint k=0;k10;k {ts[k].join;}
16 System.out.printlnarr;
17 }
18 }
上述代码第2行,申明了一个内含10个元素的数组。第3行定义的线程对数组内10个元素进行累加操作,每个元素各加1000次。第11行,开启10个这样的线程。因此,可以预测,如果线程安全,数组内10个元素的值必然都是10000。反之,如果线程不安全,则部分或者全部数值会小于10000。
程序的输出结果如下:
[10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000]
这说明AtomicIntegerArray确实合理地保证了数组的线程安全性。