Java
Java多线程
JUC相关

Java多线程 13 - AtomicReference详解

简介:AtomicReference的作用则是对对象进行原子操作。

1. AtomicReference详解

AtomicReference的作用则是对对象进行原子操作。

1.1. AtomicReference API列表

  • // 使用 null 初始值创建新的AtomicReference
  • AtomicReference()
  • // 使用给定的初始值创建新的AtomicReference
  • AtomicReference(V initialValue)
  • // 如果当前值等于预期值,则以原子方式将该值设置为给定的更新值
  • boolean compareAndSet(V expect, V update)
  • // 获取当前值
  • V get()
  • // 以原子方式设置为给定值,并返回旧值
  • V getAndSet(V newValue)
  • // 最终设置为给定值
  • void lazySet(V newValue)
  • // 设置为给定值
  • void set(V newValue)
  • // 返回当前值的字符串表示形式
  • String toString()
  • // 如果当前值等于预期值,则以原子方式将该值设置为给定的更新值
  • boolean weakCompareAndSet(V expect, V update)

1.2. AtomicReference源码解析

AtomicReference源码源码如下(基于JDK 1.8.0_101):

  • package java.util.concurrent.atomic;
  • import java.util.function.UnaryOperator;
  • import java.util.function.BinaryOperator;
  • import sun.misc.Unsafe;
  • public class AtomicReference<V> implements java.io.Serializable {
  • // 可以序列化
  • private static final long serialVersionUID = -1848883965231344442L;
  • // 用于CAS操作的Unsafe类
  • private static final Unsafe unsafe = Unsafe.getUnsafe();
  • // value属性在当前对象中相对于对象头的偏移量
  • private static final long valueOffset;
  • static {
  • try {
  • // 获取当前AtomicReference对象中保存的value属性相对于对象头的偏移量
  • valueOffset = unsafe.objectFieldOffset
  • (java.util.concurrent.atomic.AtomicReference.class.getDeclaredField("value"));
  • } catch (Exception ex) { throw new Error(ex); }
  • }
  • // 实际存储对象的属性
  • private volatile V value;
  • // 传入一个对象构造AtomicReference
  • public AtomicReference(V initialValue) {
  • value = initialValue;
  • }
  • public AtomicReference() {
  • }
  • // 获得当前的对象
  • public final V get() {
  • return value;
  • }
  • // 设置当前的对象为新对象
  • public final void set(V newValue) {
  • value = newValue;
  • }
  • // 延时设置变量值,最后设置为给定值。
  • public final void lazySet(V newValue) {
  • unsafe.putOrderedObject(this, valueOffset, newValue);
  • }
  • // CAS方式更新value
  • public final boolean compareAndSet(V expect, V update) {
  • return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
  • }
  • // 同compareAndSet
  • public final boolean weakCompareAndSet(V expect, V update) {
  • return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
  • }
  • // CAS方式设置value为新值,并返回旧值
  • @SuppressWarnings("unchecked")
  • public final V getAndSet(V newValue) {
  • return (V)unsafe.getAndSetObject(this, valueOffset, newValue);
  • }
  • // CAS方式通过UnaryOperator更新value,并返回旧值
  • public final V getAndUpdate(UnaryOperator<V> updateFunction) {
  • V prev, next;
  • do {
  • prev = get();
  • next = updateFunction.apply(prev);
  • } while (!compareAndSet(prev, next));
  • return prev;
  • }
  • // CAS方式通过UnaryOperator更新value,并返回新值
  • public final V updateAndGet(UnaryOperator<V> updateFunction) {
  • V prev, next;
  • do {
  • prev = get();
  • next = updateFunction.apply(prev);
  • } while (!compareAndSet(prev, next));
  • return next;
  • }
  • // CAS方式通过UnaryOperator将x作为参数更新value,并返回旧值
  • public final V getAndAccumulate(V x,
  • BinaryOperator<V> accumulatorFunction) {
  • V prev, next;
  • do {
  • prev = get();
  • next = accumulatorFunction.apply(prev, x);
  • } while (!compareAndSet(prev, next));
  • return prev;
  • }
  • // CAS方式通过UnaryOperator将x作为参数更新value,并返回新值
  • public final V accumulateAndGet(V x,
  • BinaryOperator<V> accumulatorFunction) {
  • V prev, next;
  • do {
  • prev = get();
  • next = accumulatorFunction.apply(prev, x);
  • } while (!compareAndSet(prev, next));
  • return next;
  • }
  • public String toString() {
  • return String.valueOf(get());
  • }
  • }

有了之前的AtomicLong和AtomicLongArray的基础,AtomicReference的源码比较简单。它是通过volatile和Unsafe提供的CAS函数实现原子操作。value是volatile类型。这保证了当某线程修改value的值时,其他线程看到的value值都是最新的value值,即修改之后的volatile的值。通过CAS设置value,这保证了当某线程池通过CAS函数(如compareAndSet函数)设置value时,它的操作是原子的,即线程在操作value时不会被中断。

2. AtomicReference示例

  • public class AtomicReferenceTest {
  • public static void main(String[] args) {
  • // 创建两个Person对象,它们的id分别是101和102
  • Person p1 = new Person(101);
  • Person p2 = new Person(102);
  • // 新建AtomicReference对象,初始化它的值为p1对象
  • AtomicReference atomicReference = new AtomicReference(p1);
  • // 通过CAS设置atomicReference,如果atomicReference的值为p1的话,则将其设置为p2
  • atomicReference.compareAndSet(p1, p2);
  • Person p3 = (Person) atomicReference.get();
  • System.out.println("p3 is " + p3);
  • System.out.println("p3.equals(p1): " + p3.equals(p1));
  • }
  • }
  • class Person {
  • volatile long id;
  • public Person(long id) {
  • this.id = id;
  • }
  • @Override
  • public boolean equals(Object o) {
  • if (this == o) return true;
  • if (!(o instanceof Person)) return false;
  • Person person = (Person) o;
  • return id == person.id;
  • }
  • @Override
  • public int hashCode() {
  • return Objects.hash(id);
  • }
  • public String toString() {
  • return "id:" + id;
  • }
  • }

运行结果如下:

  • p3 is id:102
  • p3.equals(p1): false