java.util.concurrent.atomic包一共提供了13个类,属于4中类型的原子更新方式:原子更新基本数据类型、原子更新数组、原子更新引用、原子更新属性。
>java.util.concurrent.atomic包提供了以下3个类:
- AtomicBoolean:原子更新布尔类型
- AtomicInteger : 原子更新整型
- AtomicLong:原子更新整型
以上三个类提供的方法几乎一样,下面只分析AtomicInteger:
- int addAndGet(int delta):以原子方式将输入的数值与实例中的数值(value)相加,并返回结果
- boolean compareAndSet(int expect,int update):如果输入的数值等于预期值,则以原子方式将该值设置为输入的值
int getAndIncrement():以原子方式将当前值加1,但是,返回的是自增前的值
void lazySet(int newValue):最终会设置成newValue,使用lazySet设置值后,可能导致其线程在之后的一小段时间内还是可以读到旧的值。
- int getAndSet(int newValue):以原子方式设置为newValue的值,并返回旧值。
通过getAndIncrement方法来看看实现原理:
public final int getAndIncrement() {
for (;;) {
int current = get();//先取得AtomicInteger存储的数组
int next = current + 1;//对当前数组加1
if (compareAndSet(current, next))//CAS操作更新,先检查当前数值是否等于current,如果是则将AtomicInteger的当前数组更新成next;如果不是,则返回false,重新循环更新
return current;//返回更新前的值
}
}
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
如何原子的更新其他的基本类型?
由于java.util.concurrent.atomic包的类都是使用Unsafe实现的,先看一下Unsafe的源码:
public native boolean compareAndSwapObject(Object obj, long offset,Object expect, Object update);
public native boolean compareAndSwapLong(Object obj, long offset,long expect, long update);
public native boolean compareAndSwapInt(Object obj, long offset,int expect, int update);
通过Unsafe源码分析可知,只提供了3中CAS操作,分别是compareAndSwapObject、compareAndSwapLong、compareAndSwapInt
我们在看一下AtomicBoolean类的实现:
public final boolean compareAndSet(boolean expect, boolean update) {
int e = expect ? 1 : 0;//转换成int类型
int u = update ? 1 : 0;//转换成int类型
return unsafe.compareAndSwapInt(this, valueOffset, e, u);
}
通过以上代码可以发现,AtomicBoolean先把boolean类型的参数转换成int类型,然后再调用Unsafe的compareAndSwapInt来进行CAS操作。因此,对于char、float、double类型的变量也可以用类似的思路实现。
java.util.concurrent.atomic包提供了3个原子更新数组的类:
AtomicReferenceArray:原子更新引用类型数组里的元素
AtomicInter常用方法如下:
addAndGet(int i,int delta):以原子方式将输入值与数组中索引i的元素相加。
public class Test {
static int[] value = new int[]{1,2};
static AtomicIntegerArray ai = new AtomicIntegerArray(value);
public static void main(String[] args){
ai.getAndSet(0, 3);
System.out.println(ai.get(0));
System.out.println(value[0]);
}
}
输出结果为:
3
1
如果要原子更新多个变量,需要使用原子更新引用类型提供的类。java.util.concurrent.atomic包提供了3个类:
AtomicReference示例如下:
public class AtomicReferenceTest {
static class User{
private String name;
private int old;
public User(String name,int old){
this.name=name;
this.old=old;
}
public String getName() {
return name;
}
public int getOld() {
return old;
}
}
public static AtomicReference atomicReference=new AtomicReference();
public static void main(String[] args){
AtomicReferenceTest.User user = new User("Tom", 15);
atomicReference.set(user);
User updateUser = new User("Jack",16);
atomicReference.compareAndSet(user, updateUser);
System.out.println(atomicReference.get().getName());
System.out.println(atomicReference.get().getOld());
}
}
输出结果:
jack
16
如果需要原子更新某个类的字段时,需要使用原子更新字段类,java.util.concurrent.atomic提供了3个类:
原子更新类的字段,需要两步:
AtomicIntegerFieldUpdater示例如下:
public class AtomicIntegerFieldUpdaterTest {
static class User{
private String name;
private int old;
public User(String name,int old){
this.name=name;
this.old=old;
}
public String getName() {
return name;
}
public int getOld() {
return old;
}
}
private static AtomicIntegerFieldUpdater aifu = AtomicIntegerFieldUpdater.newUpdater(User.class,"old");
public static void main(String[] args){
User user = new User("Tom", 15);
System.out.println(aifu.getAndIncrement(user));//old加1,但是仍然会输出15
System.out.println(aifu.get(user));//16
}
}
输入结果如下;
15
16