gpt4 book ai didi

Java ConcurrentHashMap.computeIfPresent 值修改可见性

转载 作者:搜寻专家 更新时间:2023-10-30 19:45:41 25 4
gpt4 key购买 nike

假设我有一个以集合作为值的并发映射:

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

后会在列表中看到值 5

我的问题是,如果更改是在 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com