首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >关于AtomicReference getAndUpdate的困惑

关于AtomicReference getAndUpdate的困惑
EN

Stack Overflow用户
提问于 2021-08-27 20:44:52
回答 1查看 565关注 0票数 1

对于AtomicReference getAndUpdate如何保证原子性,我有点困惑。请考虑以下示例

例1

代码语言:javascript
复制
AtomicReference<Set<String>> set = new AtomicReference<>(new HashSet<>());
set.getAndUpdate(current -> {
    Set<String> updated = new HashSet<>();
    updated.add("test");
    return updated;
});

例2

代码语言:javascript
复制
AtomicReference<Set<String>> set = new AtomicReference<>(new HashSet<>());
set.getAndUpdate(current -> {
    current.add("test");
    return current;
});

在示例2中,将在getAndUpdate的回调中修改集合。如果多个线程试图同时访问此函数,那么它们会看到修改后的状态还是getAndUpdate在将原始集传递给回调时通过克隆原始集来防止这种情况,这样在一个线程中就不会看到其他线程中的修改了吗?如果示例2不能保证原子性,为什么getAndUpdate允许我们编写这段代码?

示例1将保证原子性,因为修改发生在新集合上。但是它是怎么从下面来的呢?

代码语言:javascript
复制
AtomicReference<Set<String>> set = new AtomicReference<>(new HashSet<>());
Set<String> updated = new HashSet<>();
updated.add("test");
set.set(updated);
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-08-27 21:03:49

在示例2中,集合将在getAndUpdate的回调中进行修改。如果多个线程试图同时访问此函数,那么它们会看到修改后的状态还是getAndUpdate在将原始集传递给回调时通过克隆原始集来防止这种情况,这样在一个线程中就不会看到其他线程中的修改了吗?

没有什么可以阻止多个线程看到对集合的修改。只有对引用的更改是原子性的,而不是对引用所引用的任何内容的更改。

如果示例2不能保证原子性,为什么getAndUpdate允许我们编写这段代码?

因为它阻止不了你。编译器不够聪明,不知道示例2是坏代码。

为了最小化意外/不安全地修改共享状态的风险,确保存储在原子引用中的东西是不可变的,或者至少是不可修改的:

代码语言:javascript
复制
AtomicReference<Set<String>> set = new AtomicReference<>(Collections.emptySet());

set.getAndUpdate(current -> {
  Set<String> updated = new HashSet<>();
  updated.add("test");
  return Collections.unmodifiableSet(updated);
});

// or if you're on Java 9+ 
set.getAndUpdate(current -> {
  return Set.of("test");
}

示例1将保证原子性,因为修改发生在新集合上。但是它是如何脱离AtomicReference.set()的呢?

示例1使用AtomicReference.getAndUpdate,它返回前一个值,并允许您根据前面的值生成新值。如果不需要知道前一个值是什么,只需调用AtomicReference.set

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68959187

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档