我们什么时候使用 AtomicReference
?
是否需要在所有多线程程序中创建对象?
提供一个应该使用 AtomicReference 的简单示例。
原文由 Chintu 发布,翻译遵循 CC BY-SA 4.0 许可协议
我们什么时候使用 AtomicReference
?
是否需要在所有多线程程序中创建对象?
提供一个应该使用 AtomicReference 的简单示例。
原文由 Chintu 发布,翻译遵循 CC BY-SA 4.0 许可协议
当您需要更新多个线程访问的内容(在不可变对象中)时,原子引用是理想的选择,方法是将其替换为这些线程之间共享的(不可变对象的)新副本。这是一个超级密集的陈述,所以我会把它分解一下。
首先,不可变对象是在构造后实际上不会更改的对象。通常,不可变对象的方法会返回同一类的新实例。一些示例包括包装类 Long
和 Double
以及 String
,仅举几例。 (根据 Programming Concurrency on the JVM ,不可变对象是现代并发的关键部分。)
接下来,为什么 AtomicReference
比 volatile
共享该共享值的对象更好?一个简单的代码示例将显示差异。
volatile String sharedValue;
static final Object lock = new Object();
void modifyString() {
synchronized (lock) {
sharedValue = sharedValue + "something to add";
}
}
每次你想根据它的当前值修改那个 volatile 字段引用的字符串时,你首先需要获得对该对象的锁定。这可以防止其他线程在此期间进入并更改新字符串连接中间的值。然后当你的线程恢复时,你破坏了另一个线程的工作。但老实说,该代码可以工作,看起来很干净,而且会让大多数人满意。
轻微问题。它很慢。特别是如果该锁对象有很多争用。那是因为大多数锁都需要 OS 系统调用,并且您的线程将阻塞并被上下文切换出 CPU 以为其他进程让路。
另一种选择是使用 AtomicReference。
public static AtomicReference<String> shared = new AtomicReference<>();
String init = "Inital Value";
shared.set(init);
//now we will modify that value
boolean success = false;
while (!success) {
String prevValue = shared.get();
// do all the work you need to
String newValue = shared.get() + "let's add something";
// Compare and set
success = shared.compareAndSet(prevValue, newValue);
}
为什么这样更好?老实说,这段代码比以前更不干净了。但是在 AtomicRefrence 的幕后发生了一些非常重要的事情,那就是比较和交换。使切换发生的是单个 CPU 指令,而不是操作系统调用。那是 CPU 上的一条指令。而且因为没有锁,所以在锁被行使的情况下没有上下文切换,从而节省了更多时间!
问题是,对于 AtomicReferences,这不使用 .equals()
调用,而是使用 ==
比较预期值。因此,请确保 expected 是循环中从 get 返回的实际对象。
原文由 Erik Helleren 发布,翻译遵循 CC BY-SA 4.0 许可协议
15 回答8.4k 阅读
8 回答6.2k 阅读
1 回答4k 阅读✓ 已解决
3 回答2.2k 阅读✓ 已解决
2 回答3.1k 阅读
2 回答3.8k 阅读
3 回答1.7k 阅读✓ 已解决
原子引用应该用在需要对引用执行简单 _原子_(即 线程安全、非平凡)操作的设置中,基于监视器的同步不适合。假设您只想在处理过程中对象的状态发生变化时才设置特定字段:
由于原子引用语义,即使
cache
对象在线程之间共享,您也可以这样做,而不使用synchronized
。一般来说,你最好使用同步器或java.util.concurrent
框架而不是裸Atomic*
除非你知道你在做什么。两个优秀的死树参考将向您介绍这个主题:
请注意(我不知道这是否一直是真的) 引用 分配(即
=
)本身是原子的(更新 原始 64 位类型,如long
或double
可能不是原子的;但更新 引用 始终是原子的,即使它是 64 位的)没有明确使用Atomic*
。请参阅 Java 语言规范 3ed, 第 17.7 节。