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
方法需要确保最终只有一个线程的更新能够成功。