文章目录
JDK1.5 开始提供了 Java.util.concurrent.atomic包,基本上都是使用 Unsafe 实现的包装类。
1. 原子更新基本类型类
1.1 类
- AtomicBoolean: 原子更新布尔类型
- AtomicInteger: 原子更新整型
- AtomicLong: 原子更新长整型
1.2 方法
- int addAndGet(int delta): 以原子方式将输入的数值与实例中的值(AtomicInteger里的 value)相加,并返回结果,效果类似 ++i。
- boolean compareAndSet(int expect, int update): 如果输入的数值等于预期值,则以原子方式将该值设置为输入的值。
- int getAndIncrement(): 以原子方式将当前值加1,注意,这里返回的是自增前的值,效果类似 i++。
- void lazySet(int newValue): 最终会设置成 newValue,使用 LazySet设置值后,可能导致其他线程在之后的一小段时间内还是可以读到旧的值。
- int getAndSet(int newValue): 以原子方式设置为 newValue 的值,并返回旧值。
1.3 实现原理
AtomicInteger.java源码
public final int getAndIncrement(){
for(;;){
int current = get();
int next = current + 1;
if(compareAndSet(current, next))
return current;
}
}
public final boolean compareAndSet(int expect, int update){
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
1.4 Unsafe源码
Unsafe 只提供了以下3种CAS方法,AtomicBoolean实际是先把 Boolean 转成整型,再使用 compareAndSwapInt 进行 CAS,所以原子更新 char、float和double变量也可以用类似的思路来实现。
Unsafe.java源码
/**
* 如果当前数值是 expected,则原子地将 Java 变量更新成 x
* @return 如果更新成功者返回 true
*/
public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x);
public final native boolean compareAndSwapInt(Object o, long offset, int expected, Object x);
public final native boolean compareAndSwapLong(Object o, long offset, long expected, long x);
2. 原子更新数组
2.1 类
- AtomicIntegerArray: 原子更新整型数组里的元素。
- AtomicLongArray: 原子更新长整型数组里的元素。
- AtomicReferenceArray: 原子更新引用类型数组里的元素。
2.2 方法
- int addAndGet(int i, int delta): 以原子方式将输入值与数组中索引 i 的元素相加。
- boolean compareAndSet(int i, int expect, int update): 如果当前值等于预期值,则以原子方式将数组位置 i 的元素设置成 update 值。
注意:使用带参构造方法AtomicIntegerArray(int[] value)创建对象时,会将当前value数组复制一份,所以当 AtomicIntegerArray 对内部的数组元素进行修改时,不会影响传入的数组。
3. 原子更新引用类型
3.1 类
- AtomicReference: 原子更新引用类型
- AtomicReferenceFieldUpdater: 原子更新引用类型里的字段
- AtomicMarkableReference: 原子更新带有标记位的引用类型。可以原子更新一个布尔类型的标记位和引用类型。构造方法 AtomicMarkableReference(V initialRef, Boolean initialMark)。
4. 原子更新字段类
4.1 类
- AtomicIntegerFieldUpdater: 原子更新整型的字段的更新器。
- AtomicLongFieldUpdater: 原子更新长整型字段的更新器。
- AtomicStampedReference: 原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可以解决使用CAS进行原子更新时可能出现的ABA问题。
4.2 需要注意的点
- 因为原子更新字段类都是抽象类,每次使用时必须使用静态方法 newUpdate() 创建一个更新器,并且设置想要更新的类和属性。
- 更新类的字段(属性)必须使用 public volatile 修饰符。
4.3 示例代码
public class AtomicIntegerFieldUpdaterTest{
//创建原子更新器,并设置需要更新的对象类和字段名
private static AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater.newUpdater(User.class, "old");
public static void main(String[] args){
//设置柯南的年龄是10岁
User conan = new User("conan", 10);
//柯南长了一岁,但是仍然会输出旧的年龄
System.out.println(a.getAndIncrement(conan));
//输出柯南现在的年龄
System.out.println(a.get(connan));
}
public static class User{
private String name;
//需要更新的字段必须使用 public volatile 修饰符
public volatile int old;
public User(String name, int old){
this.name = name;
this.old = old;
}
public String getName(){
return name;
}
public int getOld(){
return old;
}
}
}