【Java原理系列】 Java AtomicReference由来原理用法源码详解

Java AtomicReference由来原理用法源码详解


AtomicReference类,它是一个可以原子更新的对象引用。 AtomicReference是Java并发包中的一部分,用于在多线程环境下进行原子操作。

由来

AtomicReference类的由来可以追溯到Java 5(JDK 1.5)版本。在引入并发编程包java.util.concurrent.atomic之前,Java提供了synchronized关键字和volatile关键字来实现线程安全和可见性。

然而,使用synchronized关键字需要显式地创建锁对象,并对共享数据进行加锁和解锁操作,这在复杂的多线程程序中容易出现死锁、性能瓶颈和代码复杂度增加等问题。

为了更好地支持高并发环境下的线程安全操作,Java 5引入了java.util.concurrent.atomic包,其中就包含了AtomicReference类。AtomicReference类通过原子操作实现了对对象引用的原子更新,避免了显式加锁和解锁的开销。

AtomicReference类的设计目标是提供一种简单且高效的方式来进行原子级别的引用更新。它允许开发者以原子方式修改引用,同时保持线程安全和可见性,避免了手动同步和锁的使用。

通过使用AtomicReference,开发者可以在多线程环境下安全地进行对象引用的更新操作,而无需自己编写同步代码或使用锁。这使得并发编程更加简单、高效,并且减少了潜在的线程安全问题。

总之,AtomicReference类的由来是为了提供一种高效、线程安全的方式来进行对象引用的原子更新,以满足并发编程中对性能和可见性的需求。

原理机制

AtomicReference类通过使用volatile关键字和CAS(Compare and Swap)操作来实现原子更新。

  • volatile关键字:value字段被声明为volatile,这意味着对它的读取和写入都具有可见性。当一个线程修改了value的值后,其他线程可以立即看到最新的值,而不会使用过期的缓存副本。

  • Unsafe类:Unsafe是JDK内部提供的一个工具类,允许直接操作内存和执行底层的CAS操作。在AtomicReference中,通过Unsafe.getUnsafe()获取Unsafe的实例,然后使用它来执行原子操作。

  • compareAndSwapObject方法:compareAndSwapObject方法是Unsafe类提供的一个原子操作,用于比较当前值与期望值是否相等,如果相等则将新值设置进去。这个操作是原子的,确保只有一个线程能够成功修改值,其他线程将会失败。

AtomicReference类提供了一系列原子操作的方法,如compareAndSetgetAndSet等。这些方法都是基于CAS操作来实现的,确保对value字段的读写操作是原子的、线程安全的,并且能够保证数据的一致性。

使用AtomicReference可以避免使用锁机制进行同步,从而提高多线程程序的性能和并发性。它可以在并发编程中用于实现非阻塞算法、线程安全的数据结构和其他需要原子更新的场景。

方法总结

  • valueOffset:通过反射获取value字段的偏移量。
  • value:使用volatile修饰的变量,表示当前的值。
  • 构造函数:创建一个具有给定初始值的AtomicReference对象。
  • get():获取当前的值。
  • set(V newValue):设置为给定的值。
  • lazySet(V newValue):最终将值设置为给定的值。
  • compareAndSet(V expect, V update):如果当前值等于期望值,则以原子方式将值设置为更新值。
  • weakCompareAndSet(V expect, V update):与compareAndSet类似,但不提供强制顺序保证。
  • getAndSet(V newValue):以原子方式设置为给定的值,并返回旧值。
  • getAndUpdate(UnaryOperator<V> updateFunction):以原子方式应用给定函数对当前值进行更新,并返回旧值。
  • updateAndGet(UnaryOperator<V> updateFunction):以原子方式应用给定函数对当前值进行更新,并返回新值。
  • getAndAccumulate(V x, BinaryOperator<V> accumulatorFunction):以原子方式将给定值和当前值应用于给定函数,并返回旧值。
  • accumulateAndGet(V x, BinaryOperator<V> accumulatorFunction):以原子方式将给定值和当前值应用于给定函数,并返回新值。
  • toString():返回当前值的字符串表示。

AtomicReference类提供了一种在多线程环境下进行原子操作的方式,特别适用于需要保证数据一致性的场景。它可以用于实现非阻塞算法、线程安全的数据结构和并发编程中的其他需求。

示例

以下是使用 Java 的 AtomicReference 类的示例:

import java.util.concurrent.atomic.AtomicReference;

public class AtomicReferenceExample {
    public static void main(String[] args) {
        // 创建一个初始值为 null 的 AtomicReference 对象
        AtomicReference<String> atomicRef = new AtomicReference<>();

        // 设置引用的值
        atomicRef.set("Hello");

        // 获取引用的值
        String value = atomicRef.get();
        System.out.println("Value: " + value);  // Output: Value: Hello

        // 比较并设置引用的值
        boolean exchanged = atomicRef.compareAndSet("Hello", "World");
        System.out.println("Exchanged: " + exchanged);  // Output: Exchanged: true

        // 获取更新后的值
        String updatedValue = atomicRef.get();
        System.out.println("Updated Value: " + updatedValue);  // Output: Updated Value: World
    }
}

在这个示例中,我们创建了一个 AtomicReference 对象 atomicRef,并设置初始值为 null。然后我们使用 set() 方法将引用的值设置为 “Hello”。通过调用 get() 方法,我们可以获取引用的当前值。

接下来,我们使用 compareAndSet() 方法将引用的值从 “Hello” 替换为 “World”。该方法会返回一个布尔值,表示替换是否成功。在本例中,由于引用的当前值与期望的值相匹配,所以替换操作成功,返回值为 true

最后,我们再次调用 get() 方法,获取更新后的值,并将其打印出来。

AtomicReference 类提供了原子操作,可以确保在并发环境下对引用值的操作是线程安全的。它适用于需要对共享引用进行原子更新的场景。

中文源码:

package java.util.concurrent.atomic;
import java.util.function.UnaryOperator;
import java.util.function.BinaryOperator;
import sun.misc.Unsafe;

/**
 * 一个可原子更新的对象引用。请参阅{@link java.util.concurrent.atomic}包规范,了解原子变量的属性描述。
 * @since 1.5
 * @author Doug Lea
 * @param <V> 引用的对象类型
 */
public class AtomicReference<V> implements java.io.Serializable {
    private static final long serialVersionUID = -1848883965231344442L;

    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;

    static {
        try {
            // 使用反射获取value字段的偏移量
            valueOffset = unsafe.objectFieldOffset
                (AtomicReference.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

    private volatile V value;

    /**
     * 使用给定的初始值创建一个新的AtomicReference。
     *
     * @param initialValue 初始值
     */
    public AtomicReference(V initialValue) {
        // 初始化value为初始值
        value = initialValue;
    }

    /**
     * 创建一个具有空初始值的新AtomicReference。
     */
    public AtomicReference() {
    }

    /**
     * 获取当前的值。
     *
     * @return 当前值
     */
    public final V get() {
        return value;
    }

    /**
     * 设置为给定的值。
     *
     * @param newValue 新值
     */
    public final void set(V newValue) {
        value = newValue;
    }

    /**
     * 最终设置为给定的值。
     *
     * @param newValue 新值
     * @since 1.6
     */
    public final void lazySet(V newValue) {
        unsafe.putOrderedObject(this, valueOffset, newValue);
    }

    /**
     * 如果当前值等于期望值,则以原子方式将值设置为更新值。
     *
     * @param expect 期望值
     * @param update 新值
     * @return 如果成功则返回true。返回false表示实际值与期望值不相等。
     */
    public final boolean compareAndSet(V expect, V update) {
        return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
    }

    /**
     * 如果当前值等于期望值,则以原子方式将值设置为更新值。
     *
     * <p><a href="package-summary.html#weakCompareAndSet">可能会出现错误,并且不提供排序保证</a>,
     * 因此很少是`compareAndSet`的合适替代品。
     *
     * @param expect 期望值
     * @param update 新值
     * @return 如果成功则返回true
     */
    public final boolean weakCompareAndSet(V expect, V update) {
        return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
    }

    /**
     * 原子地设置为给定值,并返回旧值。
     *
     * @param newValue 新值
     * @return 旧值
     */
    @SuppressWarnings("unchecked")
    public final V getAndSet(V newValue) {
        return (V)unsafe.getAndSetObject(this, valueOffset, newValue);
    }

    /**
     * 原子地使用给定函数对当前值进行更新,并返回旧值。该函数应该是无副作用的,
     * 因为在尝试更新失败时可能会重新应用该函数。
     *
     * @param updateFunction 无副作用的函数
     * @return 旧值
     * @since 1.8
     */
    public final V getAndUpdate(UnaryOperator<V> updateFunction) {
        V prev, next;
        do {
            prev = get();
            next = updateFunction.apply(prev);
        } while (!compareAndSet(prev, next));
        return prev;
    }

    /**
     * 原子地使用给定函数对当前值进行更新,并返回新值。该函数应该是无副作用的,
     * 因为在尝试更新失败时可能会重新应用该函数。
     *
     * @param updateFunction 无副作用的函数
     * @return 新值
     * @since 1.8
     */
    public final V updateAndGet(UnaryOperator<V> updateFunction) {
        V prev, next;
        do {
            prev = get();
            next = updateFunction.apply(prev);
        } while (!compareAndSet(prev, next));
        return next;
    }

    /**
     * 原子地使用给定函数将当前值和给定值应用于更新,并返回旧值。
     * 该函数应该是无副作用的,因为在尝试更新失败时可能会重新应用该函数。
     *
     * @param x 更新值
     * @param accumulatorFunction 两个参数的无副作用函数
     * @return 旧值
     * @since 1.8
     */
    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;
    }

    /**
     * 原子地使用给定函数将当前值和给定值应用于更新,并返回新值。
     * 该函数应该是无副作用的,因为在尝试更新失败时可能会重新应用该函数。
     *
     * @param x 更新值
     * @param accumulatorFunction 两个参数的无副作用函数
     * @return 新值
     * @since 1.8
     */
    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;
    }

    /**
     * 返回当前值的字符串表示。
     * @return 当前值的字符串表示
     */
    public String toString() {
        return String.valueOf(get());
    }

}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BigDataMLApplication

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值