【悲观锁】Synchronized和ReentrantLock的区别
【线程方法】多线程下 wait、notify、park、unpark 和 await、signal 的区别
【同步工具】CyclicBarrier和CountDownLatch的区别
AtomicReference 是 Java 中 java.util.concurrent.atomic 包下提供的原子引用类。它用于在多线程环境下原子性地更新引用类型的对象。与 AtomicInteger 类似,AtomicReference 的实现也基于 CAS(Compare-And-Swap)操作
1、AtomicReference 的主要方法:
1、get(): 获取当前引用的值。
AtomicReference<String> atomicRef = new AtomicReference<>("Initial Value");
String value = atomicRef.get();
2、set(newValue): 设置引用的新值。
AtomicReference<String> atomicRef = new AtomicReference<>("Initial Value");
atomicRef.set("New Value");
3、getAndSet(newValue): 获取当前引用的值,并设置新值。
AtomicReference<String> atomicRef = new AtomicReference<>("Initial Value");
String oldValue = atomicRef.getAndSet("New Value");
4、compareAndSet(expectedValue, newValue): 比较当前引用的值是否等于期望值,如果相等则设置新值。
AtomicReference<String> atomicRef = new AtomicReference<>("Initial Value");
boolean success = atomicRef.compareAndSet("Initial Value", "New Value");
示例
import java.util.concurrent.atomic.AtomicReference;
public class AtomicReferenceExample {
public static void main(String[] args) {
AtomicReference<String> atomicRef = new AtomicReference<>("Initial Value");
// 获取当前值
String currentValue = atomicRef.get();
System.out.println("Current Value: " + currentValue);
// 设置新值
atomicRef.set("New Value");
System.out.println("Updated Value: " + atomicRef.get());
// 获取并设置新值
String oldValue = atomicRef.getAndSet("Another Value");
System.out.println("Old Value: " + oldValue);
System.out.println("Current Value: " + atomicRef.get());
// 比较并设置新值
boolean success = atomicRef.compareAndSet("Another Value", "Success");
System.out.println("CAS Operation Successful? " + success);
System.out.println("Current Value: " + atomicRef.get());
}
}
2、原子引用ABA问题
"ABA 问题" 是在使用 CAS等原子操作时可能出现的一种情况。具体来说,它涉及到一个变量从 A 变成 B,然后再变回 A 的过程。
假设有线程 T1 在执行 CAS 操作时,读取了一个共享变量的值为 A,然后线程 T2 将这个变量的值修改为 B,最后线程 T2再将其修改回 A。在 T1 执行 CAS 操作时,由于变量的值仍然是 A,最终CAS 操作成功,但实际上中间发生了其他线程的干扰,使得变量的含义发生了变化。
这个问题可能导致程序在使用 CAS 操作进行数据同步时出现错误,因为 CAS 只能判断变量的当前值是否与预期值相等,而无法判断变量在操作过程中是否发生了变化。
解决ABA问题的方法1:
AtomicStampedReference 是 Java 中 java.util.concurrent.atomic 包下提供的原子引用类之一。它通过引入一个“标记”(stamp)来解决 CAS 操作中的 ABA 问题。每次更新引用时,同时也会更新对应的标记,从而增加了对变量状态的判断。
import java.util.concurrent.atomic.AtomicStampedReference;
public class AtomicStampedReferenceExample {
public static void main(String[] args) {
AtomicStampedReference<String> atomicRef = new AtomicStampedReference<>("Initial Value", 0);
// 获取当前值和标记
String currentValue = atomicRef.getReference();
int currentStamp = atomicRef.getStamp();
System.out.println("Current Value: " + currentValue);
System.out.println("Current Stamp: " + currentStamp);
// 设置新值和新标记
atomicRef.set("New Value", 1);
System.out.println("Updated Value: " + atomicRef.getReference());
System.out.println("Updated Stamp: " + atomicRef.getStamp());
// 尝试将引用的值从 "Initial Value" 更新为 "New Value",版本戳为 0
boolean success = atomicRef.compareAndSet("Initial Value", "New Value", 0, 1);
System.out.println("CAS Operation Successful? " + success);
System.out.println("Current Value: " + atomicRef.getReference());
System.out.println("Current Stamp: " + atomicRef.getStamp());
}
}
解决ABA问题的方法2:
使用 AtomicMarkableReference 解决 ABA 问题,适用于你只想知道这个数据改没改,并不care改了几次。
import java.util.concurrent.atomic.AtomicMarkableReference;
public class AtomicMarkableReferenceExample {
public static void main(String[] args) {
// 创建一个 AtomicMarkableReference,初始引用为 0,标记位为 false
AtomicMarkableReference<Integer> atomicRef = new AtomicMarkableReference<>(0, false);
// 线程1:尝试更新引用值
Thread t1 = new Thread(() -> {
Integer oldValue = atomicRef.getReference();
boolean oldMark = atomicRef.isMarked();
System.out.println("线程1初始值: " + oldValue + ", 标记位: " + oldMark);
// 线程1将引用值修改为 1,标记位保持不变
boolean updated = atomicRef.compareAndSet(oldValue, 1, oldMark, oldMark);
System.out.println("线程1更新引用值: " + updated);
});
// 线程2:尝试在其他线程更改引用时检查它
Thread t2 = new Thread(() -> {
Integer oldValue = atomicRef.getReference();
boolean oldMark = atomicRef.isMarked();
System.out.println("线程2初始值: " + oldValue + ", 标记位: " + oldMark);
// 线程2将引用值修改为 2,标记位为 true
boolean updated = atomicRef.compareAndSet(oldValue, 2, oldMark, true);
System.out.println("线程2更新引用值: " + updated);
});
// 启动线程
t1.start();
t2.start();
}
}
本文介绍了Java中的AtomicReference类,用于在多线程环境中原子性地更新引用类型对象,以及其主要方法如get(),set(),getAndSet(),compareAndSet()。此外,讨论了ABA问题及其在CAS操作中的影响,并提出了AtomicStampedReference作为解决方案。

996

被折叠的 条评论
为什么被折叠?



