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
类提供了一系列原子操作的方法,如compareAndSet
、getAndSet
等。这些方法都是基于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());
}
}