AtomicReference 是 Java 并发工具包 java.util.concurrent.atomic 中提供的一个类,用于实现一个可以原子读写的对象引用变量。
属性
VALUE
private static final VarHandle VALUE;这是一个 VarHandle 类型的静态变量,它是 AtomicReference 实现原子操作的关键。VarHandle 提供了直接操作变量的途径,包括原子性操作。
VALUE使用静态代码块进行初始化。
static {
try {
MethodHandles.Lookup l = MethodHandles.lookup();
VALUE = l.findVarHandle(AtomicReference.class, "value", Object.class);
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}MethodHandles.Lookup 是一个用于查找和操作 MethodHandle 的工具。MethodHandle 是一个强类型的、可变的方法指针,它可以用于在运行时直接调用方法。Lookup 类似于反射中的 Class 对象,但它提供了更细粒度的控制,尤其是在安全性和性能方面。
这行代码使用 Lookup 实例来查找并创建一个 VarHandle 对象,该对象与 AtomicReference 类中的 value 字段关联。findVarHandle 方法接受三个参数:包含目标字段的类(AtomicReference.class),字段的名称("value"),以及字段的类型(Object.class)。这个 VarHandle 对象随后被赋值给静态变量 VALUE。
value
@SuppressWarnings("serial") // Conditionally serializable
private volatile V value;这是一个 volatile 类型的变量,它持有 AtomicReference 的当前值。volatile 关键字确保了 value 的读写操作对所有线程立即可见,并且每次访问 value 都会直接从主内存中进行,而不是从线程的本地缓存中读取。这是实现原子性和内存可见性的重要部分。
构造函数

AtomicReference(V initialValue): 创建一个具有指定初始值的AtomicReference。AtomicReference(): 创建一个初始值为null的AtomicReference。
主要方法
get和set
查看代码
/**
* Returns the current value,
* with memory effects as specified by {@link VarHandle#getVolatile}.
*/
public final V get() {
return value;
}
/**
* Sets the value to {@code newValue},
* with memory effects as specified by {@link VarHandle#setVolatile}.
*/
public final void set(V newValue) {
value = newValue;
}getAndUpdate
getAndUpdate方法以原子方式更新AtomicReference中的值。这个方法接受一个UnaryOperator函数式接口的实现,这个接口的apply方法定义了如何更新值。
getAndUpdate方法的执行流程:
获取当前值:首先,方法通过调用
get()方法获取当前AtomicReference中的值,并将其存储在局部变量prev中。查看代码
javapublic final V getAndUpdate(UnaryOperator<V> updateFunction) { V prev = get(), next = null; for (boolean haveNext = false;;) { if (!haveNext) next = updateFunction.apply(prev); if (weakCompareAndSetVolatile(prev, next)) return prev; haveNext = (prev == (prev = get())); } }尝试应用更新函数:然后,方法进入一个无限循环,首先检查布尔变量
haveNext是否为false。如果是,那么调用updateFunction.apply(prev)来计算新的值next。尝试原子更新:接下来,调用
weakCompareAndSetVolatile(prev, next)方法尝试原子地更新当前值。这个方法会原子地比较AtomicReference中的当前值和prev是否相等,如果相等,则将值更新为next。- 如果更新成功(
weakCompareAndSetVolatile返回true),则方法返回原来的值prev。 - 如果更新失败(
weakCompareAndSetVolatile返回false),则表示在尝试更新期间,其他线程已经修改了AtomicReference中的值。
javapublic final boolean weakCompareAndSetVolatile(V expectedValue, V newValue) { return VALUE.weakCompareAndSet(this, expectedValue, newValue); }- 如果更新成功(
处理竞争:如果更新失败,循环会继续执行。首先,通过再次调用
get()方法更新prev的值为最新的值。然后,检查prev是否等于之前的值,如果等于,说明没有其他线程修改过这个值,可以再次使用之前计算好的next值尝试更新;如果不等于,说明其他线程已经修改了这个值,需要重新计算next。重复尝试:如果更新失败,会重复步骤2到4,直到成功更新为止。
整个过程中,getAndUpdate方法确保了原子性和可见性。原子性是通过weakCompareAndSetVolatile方法实现的,它确保了比较和设置操作的原子性。可见性是因为weakCompareAndSetVolatile使用了一种内存屏障,确保了新值对其他线程的可见性。
需要注意的是,updateFunction函数应该是无副作用的,因为它可能会在存在线程竞争的情况下被多次调用。这是因为在多线程环境中,可能会出现多个线程同时尝试更新值的情况,而getAndUpdate方法需要确保最终只有一个线程的更新能够成功。
