| 知乎专栏 |
AtomicInteger sequence = new AtomicInteger(1); sequence.getAndIncrement(); // 加1操作
package cn.aigcsst.conference.config;
import java.util.concurrent.atomic.AtomicBoolean;
public class AtomicService {
private AtomicBoolean isRunning = new AtomicBoolean(false);
// 开启服务
public void start() {
isRunning.set(true);
System.out.println("Service started.");
}
// 关闭服务
public void stop() {
isRunning.set(false);
System.out.println("Service stopped.");
}
// 检查服务是否正在运行
public boolean isRunning() {
return isRunning.get();
}
}
private static AtomicReference<BankCard> bankCardRef = new AtomicReference<>(new BankCard("Neo",100));
AtomicReference<String> atomicRef = new AtomicReference<>("Initial Value");
// 获取值
String value = atomicRef.get(); // "Initial Value"
// 设置值
atomicRef.set("New Value");
// CAS 操作
boolean success = atomicRef.compareAndSet("New Value", "Updated Value");
System.out.println(success); // true(如果当前值仍然是 "New Value")
class Singleton {
private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<>();
public static Singleton getInstance() {
while (true) {
Singleton instance = INSTANCE.get();
if (instance != null) {
return instance;
}
instance = new Singleton();
if (INSTANCE.compareAndSet(null, instance)) {
return instance;
}
}
}
private Singleton() {
// 私有构造方法
}
}
设置新值,使用 volatile 语义,确保新值对其他线程立即可见(遵循 happens-before 原则)。
AtomicReference<String> ref = new AtomicReference<>("初始值");
ref.set("新值"); // 原子性地更新为新值
AtomicReference 类中的 get() 方法是最常用的读取操作,它提供了强内存顺序保证和即时可见性。
import java.util.concurrent.atomic.AtomicReference;
public class StateControlExample {
private static final AtomicReference<State> state = new AtomicReference<>(State.INIT);
enum State { INIT, RUNNING, STOPPED }
public static void main(String[] args) throws InterruptedException {
// 工作线程
Thread worker = new Thread(() -> {
while (state.get() != State.STOPPED) {
System.out.println("工作中...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("工作线程已停止");
});
// 控制线程
Thread controller = new Thread(() -> {
try {
Thread.sleep(3000);
// 更新状态为 STOPPED
state.set(State.STOPPED);
System.out.println("已发送停止命令");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
worker.start();
controller.start();
worker.join();
controller.join();
}
}
lazySet() 提供了一种在高并发场景下以较低性能开销更新原子引用的方式,适用于对可见性要求不高、但对吞吐量敏感的场景。使用时需明确弱内存顺序的语义,避免在关键业务逻辑中引入不可见性问题。
lazySet() 的实现如下:
public final void lazySet(V newValue) {
VALUE.setRelease(this, newValue);
}
以下示例展示了 lazySet() 在标记线程状态时的应用:
import java.util.concurrent.atomic.AtomicReference;
public class LazySetExample {
private static final AtomicReference<State> state = new AtomicReference<>(State.RUNNING);
enum State { RUNNING, STOPPED }
public static void main(String[] args) throws InterruptedException {
// 工作线程
Thread worker = new Thread(() -> {
while (state.get() == State.RUNNING) {
// 执行任务...
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("工作线程已停止");
});
worker.start();
// 主线程:延迟一段时间后停止工作线程
Thread.sleep(1000);
// 使用 lazySet 设置状态,不要求立即对工作线程可见
state.lazySet(State.STOPPED);
System.out.println("已发送停止命令");
worker.join();
}
}
AtomicReference 类中的 setRelease(V newValue) 是 Java 9 引入的原子操作,它提供了释放语义(Release Semantics)的写入操作。与普通的 set() 相比,setRelease() 在内存可见性和重排序限制上有更明确的语义,同时保持了较低的性能开销。
import java.util.concurrent.atomic.AtomicReference;
public class PublishSubscribeExample {
private static final AtomicReference<String> messageRef = new AtomicReference<>(null);
public static void main(String[] args) throws InterruptedException {
// 生产者线程:准备并发布消息
Thread producer = new Thread(() -> {
// 准备数据(可能涉及多个操作)
String data = "重要消息";
int processedData = 42; // 模拟数据处理
// 使用 release 语义发布消息,确保数据准备完成后才发布
messageRef.setRelease(data);
System.out.println("消息已发布");
});
// 消费者线程:等待并读取消息
Thread consumer = new Thread(() -> {
String message;
// 使用 acquire 语义读取消息,确保看到完整的发布内容
while ((message = messageRef.getAcquire()) == null) {
System.out.println("等待消息...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("收到消息: " + message);
});
consumer.start();
producer.start();
producer.join();
consumer.join();
}
}
AtomicReference 类中的 getOpaque() 方法是 Java 9 引入的一个原子操作,它提供了一种以弱内存顺序读取引用值的方式。与 get() 方法相比,getOpaque() 的可见性保证较弱,但性能开销可能更低。
import java.util.concurrent.atomic.AtomicReference;
public class OpaqueReadExample {
private static final AtomicReference<String> ref = new AtomicReference<>("初始值");
public static void main(String[] args) {
// 线程1:更新值
Thread writer = new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
ref.set("新值");
System.out.println("写入完成: " + ref.get());
});
// 线程2:使用 getOpaque() 读取值
Thread reader = new Thread(() -> {
String value;
do {
// 使用弱内存顺序读取
value = ref.getOpaque();
System.out.println("读取到: " + value);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (!"新值".equals(value));
System.out.println("最终读取到: " + value);
});
writer.start();
reader.start();
try {
writer.join();
reader.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
AtomicReference 类中的 getAcquire() 方法是,提供了一种以获取语义(Acquire Semantics)读取引用值的方式。与 getOpaque() 相比,getAcquire() 提供了更强的内存可见性保证,但比 get() 更轻量。
import java.util.concurrent.atomic.AtomicReference;
public class PublishSubscribeExample {
private static final AtomicReference<String> messageRef = new AtomicReference<>(null);
public static void main(String[] args) {
// 生产者线程:发布消息
Thread producer = new Thread(() -> {
// 准备数据
String data = "重要消息";
// 其他操作...
// 使用 release 语义发布消息
messageRef.setRelease(data);
System.out.println("消息已发布");
});
// 消费者线程:订阅消息
Thread consumer = new Thread(() -> {
String message;
// 使用 acquire 语义读取消息
while ((message = messageRef.getAcquire()) == null) {
System.out.println("等待消息...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("收到消息: " + message);
});
consumer.start();
producer.start();
try {
producer.join();
consumer.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
AtomicReference 类中的 getPlain() 方法提供了最弱的内存顺序保证,用于读取引用值。与其他读取方法相比,getPlain() 的性能开销最低,但也牺牲了更多的内存可见性保证。
import java.util.concurrent.atomic.AtomicReference;
public class CounterExample {
private static final AtomicReference<Integer> counter = new AtomicReference<>(0);
public static void main(String[] args) throws InterruptedException {
// 写线程:递增计数器
Thread writer = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
counter.updateAndGet(v -> v + 1);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// 读线程:使用 getPlain() 读取计数器
Thread reader = new Thread(() -> {
int value;
while ((value = counter.getPlain()) < 1000) {
System.out.println("当前计数(getPlain): " + value);
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("最终计数: " + value);
});
writer.start();
reader.start();
writer.join();
reader.join();
}
}
将引用值原子性地设置为新值,并返回旧值。
AtomicReference<String> ref = new AtomicReference<>("旧值");
String oldValue = ref.getAndSet("新值");
System.out.println("旧值: " + oldValue); // 输出 "旧值"
System.out.println("新值: " + ref.get()); // 输出 "新值"