无锁的线程安全整数 AtomicInteger

为了能够受益于CAS等CPU指令,JDK并发包中有一个Atomic包,里面实现了一些直接使用CAS操作的线程安全的类型

下面是AtomicInteger的一些常用方法,对应其他原子类,操作是类似的.

内部实现上来说,AtomicInteger中保存一个核心字段

1
private volatile int value; //代表atomicInteger的当前实际取值.
1
private static final long valueOffset; //保存value字段在AtomicInteger对向中的偏移量.

一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerDemo {
static AtomicInteger i =new AtomicInteger(10);

public static class AddThread implements Runnable
{
@Override
public void run()
{
for(int k=0;k<1000;k++)
{
i.incrementAndGet();
System.out.println(i);
System.out.println(i +" "+Thread.currentThread().getId());
}
}
}

public static void main(String[] args) throws Exception
{
Thread[] ts =new Thread[10];
for(int k=0;k<10;k++)
{
ts[k]=new Thread(new AddThread());
}

for(int k=0;k<10;k++)
{
ts[k].start();
}
// for(int k=0;k<10;k++)
// {
// ts[k].join();
// }
System.out.println(i);
}
}

AtomicReference 无锁的对象引用

AtomicReference 和AtomicInteger 非常类似,不同之处在于AtomicInteger是对整数的封装,而AtomicReference对应普通的对象引用.它可以保证用户在修改对象引用时的线程安全性.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class AtomicReferenceDemo {
public static void main(String[] args){
// 创建两个Person对象,它们的id分别是101和102。
Person p1 = new Person(101);
Person p2 = new Person(102);
// 新建AtomicReference对象,初始化它的值为p1对象
AtomicReference<Person> ar = new AtomicReference<>(p1);
// 通过CAS设置ar。如果ar的值为p1的话,则将其设置为p2。
ar.compareAndSet(p1, p2);
Person p3 = ar.get();
System.out.println("p3 is "+p3);
System.out.println("p3.equals(p1)="+p3.equals(p1));
System.out.println("p3.equals(p2)="+p3.equals(p2));
}
}
class Person {
volatile long id;
public Person(long id) {
this.id = id;
}
public String toString() {
return "id:"+id;
}
}

AtomicIntegerArray 无锁的数组

除基本数据类型外,JDK还准备了数组等复合结构,

AtomicIntegerArray 本质是对int[] 类型的封装,使用UNSAFE类通过CAS的方式控制int[] 在多线程下的安全性.有如下常用API

1
2
3
4
5
6
7
public final int get(int i);//获得数组第i个下标的元素
public final int length();//获得数组的长度
public final int getAndSet(int i,int newValue)//将第i个下标的值设置为newValue,返回旧值
public final boolean compareAndSet(int i,int expect,int update)//进行CAS操作,如果第i个下标的元素等于expect,则设置为update,设置成功返回true.
public final int getAndIncrement(int i)
public final int getAndDecrement(int i)
public final int getAndAdd(int i,int delta)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class AtomicIntegerArrayDemo {
static AtomicIntegerArray array =new AtomicIntegerArray(10);
public static class AddThread implements Runnable
{
public void run()
{
for(int k=0;k<1000;k++)
{
array.getAndIncrement(k%array.length());
}
}
}
public static void main(String args[]) throws Exception
{
Thread ts[] =new Thread[10];
for(int k=0;k<10;k++)
{
ts[k]=new Thread(new AddThread());
}
for(int k=0;k<10;k++)
{
ts[k].start();
}
// for(int k=0;k<10;k++)
// {
// ts[k].join();
// }
Thread.sleep(5000); //不让主线程sleep的话,可能输出的时候,其他线程还没有运行结束.这也是前面加join的意思.
System.out.println(array);
}
}

AtomicIntegerFieldUpdater 让类中某变量也可以原子操作