- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
假设我有一个以集合作为值的并发映射:
Map<Integer, List<Integer> map = new ConcurrentHashMap<>();
map.putIfAbsent(8, new ArrayList<>());
然后我按如下方式更新值:
map.computeIfPresent(8, (i, c) -> {
c.add(5);
return c;
});
我知道 computeIfPresent
整个方法调用是原子执行的。然而,考虑到这个映射被多个线程同时访问,我有点担心对底层集合所做的修改的数据可见性。在这种情况下,调用 map.get
我的问题是,如果更改是在 computeIfPresent
方法调用中执行的,那么在调用 map.get
时,列表是否会在其他线程中可见。
请注意,我知道如果我在执行更新操作之前引用列表,则列表的更改将不可见。如果我在更新操作后引用列表(通过调用 map.get
),我不确定列表的更改是否可见。
我不确定如何解释这些文档,但在我看来,先行发生关系将保证在这种特定情况下底层集合的更改可见
More formally, an update operation for a given key bears a happens-before relation with any (non-null) retrieval for that key reporting the updated value
最佳答案
该方法被记录为原子
的事实并不意味着可见性
(除非这是文档的一部分)。例如,为了使这个更简单:
// some shared data
private List<Integer> list = new ArrayList<>();
public synchronized void addToList(List<Integer> x){
list.addAll(x);
}
public /* no synchronized */ List<Integer> getList(){
return list;
}
我们可以说addToList
确实是原子的,一次只能有一个线程调用它。但是一旦某个线程调用 getList
- 根本无法保证 visibility
(因为要建立它,it has to happens on the same lock)。因此,可见性是之前发生的事情,computeIfPresent
文档对此根本没有说明。
相反,类文档说:
Retrieval operations (including get) generally do not block, so may overlap with update operations (including put and remove).
这里的关键点显然是overlap,所以一些其他线程调用get
(从而获得那个List
),可以看到List
处于某种状态;不一定是 computeIfPresent
开始的状态(在您实际调用 get
之前)。一定要进一步阅读以理解一些实际上可能意味着什么。
现在是该文档中最棘手的部分:
Retrievals reflect the results of the most recently completed update operations holding upon their onset. More formally, an update operation for a given key bears a happens-before relation with any (non-null) retrieval for that key reporting the updated value.
再读一遍关于completed 的句子,它说的是当一个线程get
时你唯一能读到的是last completed 说明 List 所在的位置。现在下一句话说在两个 Action 之间建立了一个发生在之前。
想一想,在两个后续 操作之间建立了一个happens-before
(如上面的同步示例);所以在内部,当你更新一个 Key
时,可能会有一个不稳定的书面信号表明更新已经完成(我很确定它不是这样完成的,只是一个例子)。为了让 happens before 真正起作用,get
必须读取那个 volatile 并查看写入它的状态;如果它看到该状态,则意味着发生在之前;我想这实际上是通过其他一些技术强制执行的。
因此,为了回答您的问题,所有调用 get
的线程都将看到发生在该键上的 last completed action
;在你的情况下,如果你能保证订单,我会说,是的,它们将是可见的。
关于Java ConcurrentHashMap.computeIfPresent 值修改可见性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52577524/
我最初构造了一系列嵌套的 ConcurrentHashMaps private final ConcurrentHashMap allInOne = new ConcurrentHashMap
我正在尝试使用 ConcurrentHashMap 初始化 ConcurrentHashMap private final ConcurrentHashMap > myMulitiConcurrent
为了提高工作效率,我尝试将数据保存在一个动态容器中。 我在 class 中初始化它与 private final ConcurrentHashMap allInOne = new Concur
我正在创建基于 Socket 的服务器-客户端预订服务,并且遇到有关将由多个线程访问的类的问题,是否需要扩展 ConcurrentHashMap 或创建变量 ConcurrentHashMap 是否足
从 Javadoc 我知道 ConcurrentHashMap.replace 是原子的,但是 ConcurrentHashMap.put 呢?我看到它们在源代码中的实现方式不同,但我无法弄清楚它们的
是 ConcurrentHashMap.get() 保证看到以前的ConcurrentHashMap.put()通过不同的线程?我的期望是,阅读 JavaDocs 似乎表明了这一点,但我 99% 确信
使用 ConcurrentHashMap,我发现 computeIfAbsent 比 putIfAbsent 慢两倍。这里是简单的测试: import java.util.ArrayList; imp
我有一个以下格式的 ConcurrentHashMap: ConcurrentHashMap> 现在在此 map 中,我想删除数组列表中的特定值。任何人都可以指导这一点。 编辑1:我有一张 map >
为什么 ConcurrentHashMap.Segment 和 ConcurrentHashMap.HashEntry 类是静态的?为什么要这样设计? 最佳答案 基本上所有不需要使用其封闭类属性的内部
在 ConcurrentHashMap 中通过键递增并发计数器时,使用常规 Int 作为值是否安全,还是我们必须使用 AtomicInteger?例如考虑以下两个实现 ConcurrentHashMa
我对java中的并发数据结构有疑问,特别是: 1) ConcurrentHashMap 2) HashMap 3) ConcurrentHashMap 如果我理解正确的话: 1) 读/写是线程安全的,
我正在尝试查看实际的 Java 文档,描述传递给 ConcurrentHashMap.computeIfAbsent 和 ConcurrentHashMap.computeIfPresent< 时可以
我有一个名为 SerializableL 的接口(interface)由 3 个不同的类实现: 产品 横幅 标签 我开始重构,想用多个方法调用替换多个段落。 public void load(Conc
一 JDK 中的 ConcurrentHashMap 在 JDK 8以前,HashMap 是基于数组 + 链表来实现的。整体上看,HashMap 是一个数组,但每个数组元素又是一张链表。 当向 Has
我想知道当我们在调整大小时尝试读取 ConcurrentHashMap 时可能发生的情况。 我知道在读取期间,第一次尝试总是不同步的。在第二次尝试中,它将尝试获取锁并重试。 但是,如果它在调整大小时发
在一个应用程序中,1 个线程负责不断更新映射,主线程定期读取映射,使用 ConcurrentHashmap 是否足够?或者我应该明确地锁定同步块(synchronized block)中的操作吗?任何
介绍 ConcurrentHashMap 技术是为了解决问题而生的,ConcurrentHashMap 解决了多个线程同时操作一个 HashMap 时,可能出现的内部问题。当多个线程同时操作一
我有一个由多个线程访问的键值映射: private final ConcurrentMap key_vval_map = new ConcurrentHashMap(); 我的自定义 get() 和
谁能告诉我这段代码出了什么问题?我要拔头发了! 如果我使用 HashMap 而不是 ConcurrentHashMap 则没有任何问题。代码使用JDK 5.0编译 public class MapTe
来自 ConcurrentHashMap 的源码 /** 171 * Number of unsynchronized retries in size and containsVal
我是一名优秀的程序员,十分优秀!