AtomicReference的功能
从名字可以直观翻译出一句话: 提供了可以原子的读写对象引用的一种机制。
是AtomicReferenceXXX相关类的最基础类,还有AtomicReferenceArray、AtomicReferenceFieldUpdater、AtomicStampedReference等。
AtomicReference的接口列表(jdk1.8.0_151)
// 构造初始值为null的AtomicReference对象
public AtomicReference();
// 构造初始值为initialValue的AtomicReference对象
public AtomicReference(V initialValue)
// 获取当前value对象
public final V get()
// 直接更新volatile对象的值
public final void set(V newValue)
// 与set()方法的区别见: http://ifeve.com/juc-atomic-class-lazyset-que/
// https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6275329
// 虽然大神对使用场景做了介绍和说明,但是还是没有想出来什么样的场景会用到……-_-||
public final void lazySet(V newValue)
// 基于 == 操作进行的CAS更新
public final boolean compareAndSet(V expect, V update)
// 高效但不保证可见性的原子set操作,在无happens-before需求的场景下使用
public final boolean weakCompareAndSet(V expect, V update)
// 设置给定值,并返回旧值
public final V getAndSet(V newValue)
// 通过可重入无状态的方法更新对象值,并返回旧值
// 内部通过get + CAS自旋的策略进行
public final V getAndUpdate(UnaryOperator<V> updateFunction)
// 与上一个方法类似,只是返回更新后的新值
public final V updateAndGet(UnaryOperator<V> updateFunction)
// 回调方法可以带入参的更新操作,返回旧值
// V x作为accumulatorFunction的一个入参,accumulatorFunction.apply(prev, x)
public final V getAndAccumulate(V x,BinaryOperator<V> accumulatorFunction)
// 与上一个方法类似,返回新值
public final V accumulateAndGet(V x,BinaryOperator<V> accumulatorFunction)
关键点
- 使用CAS操作保证原子性, 使用volatile修饰保证可见性;
- 相等的比较算法是 ==,即基本数据类型判断值,对象类型判断引用地址是否相同;
public class AtomicReferenceTest {
public static void main(String[] args) {
String value = "hello world";
ReferenceObject object = new AtomicReferenceTest.ReferenceObject(value);
AtomicReference<ReferenceObject> atomicReference = new AtomicReference(object);
atomicReference.compareAndSet(object, new ReferenceObject("Hello guy!"));
System.out.println(atomicReference.get().getValue());
// 顺道测试一下Integer的常量池
AtomicReference<Integer> integerNewReference = new AtomicReference(new Integer(10));
integerNewReference.compareAndSet(new Integer(10), new Integer(-10));
System.out.println(integerNewReference.get().intValue());
AtomicReference<Integer> integerValeOfReference = new AtomicReference(Integer.valueOf(10));
integerValeOfReference.compareAndSet(new Integer(10), new Integer(-10));
System.out.println(integerValeOfReference.get().intValue());
integerValeOfReference.compareAndSet(Integer.valueOf(10), new Integer(-10));
System.out.println(integerValeOfReference.get().intValue());
}
static class ReferenceObject {
private String value;
public ReferenceObject(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
}
可以插播Integer常量池的特点, new Integer是在堆上生成一个新对象, 只有Integer对象赋值(编译时转成Integer.valueOf())或Integer.valueof且默认数值在-128 - 127才会用到常量池.
扩展
AtomicReferenceArray: 初始化时计算数组的起始位置和每个元素的偏移量,通过base + i << shift进行数组索引;
AtomicReferenceFieldUpdater: 对指定类中的volatile属性进行原子更新,一般使用不会存在问题。但如果涉及自定义类加载器的场景,需要注意需保证在同一组类加载器加载中。