gpt4 book ai didi

java - ConcurrentMap.remove() 是否在 get() 返回 null 之前提供先行边?

转载 作者:搜寻专家 更新时间:2023-10-31 19:44:11 26 4
gpt4 key购买 nike

在调用 ConcurrentMap.remove() 之前线程中的操作是否保证发生在操作之后看到从另一个线程中删除?

Documentation关于放置在集合中的对象,这是这样说的:

Actions in a thread prior to placing an object into any concurrent collection happen-before actions subsequent to the access or removal of that element from the collection in another thread.

示例代码:

{
final ConcurrentMap map = new ConcurrentHashMap();
map.put(1, new Object());

final int[] value = { 0 };

new Thread(() -> {
value[0]++;
value[0]++;
value[0]++;
value[0]++;
value[0]++;

map.remove(1); // A

}).start();

new Thread(() -> {
if (map.get(1) == null) { // B
System.out.println(value[0]); // expect 5
}

}).start();
}

AB 之间是否存在发生在之前的关系?因此,程序是否应该只打印 5?

最佳答案

您已经发现这些并发工具的一个有趣的微妙方面很容易被忽视。

首先,不可能提供关于删除和检索 null 引用的一般保证,因为后者仅证明映射不存在,而不是先前的映射删除,即在键有映射之前,线程可以读取映射的初始状态,当然,不能与 map 构建后发生的 Action 。

此外,如果有多个线程删除同一个键,则在检索 null 时,您不能假设happens-before 关系,因为您不知道哪个移除已经完成。这个问题类似于两个线程插入相同值的情况,但后者可以在应用程序端通过仅执行可区分值的插入或遵循对正在运行的值对象执行所需修改的通常模式来修复仅被插入并查询检索到的对象。对于删除,没有这样的修复。

在您的特殊情况下,map.put(1, new Object()) 操作与第二个线程的开始之间存在happens-before 关系,因此,如果第二个线程在查询键 1 时遇到 null,很明显它见证了您的代码的唯一删除,但是,规范并没有提供一个对这种特殊情况的明确保证。

相反,Java 8’s ConcurrentHashMap 的规范说,

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.)

明确排除 null 检索。

我认为,使用当前 (Java 8) ConcurrentHashMap 实现,您的代码不会中断,因为它相当保守,因为它使用 volatile 执行对其内部后备数组的所有访问 语义。但这只是当前的实现,并且如上所述,您的代码是一个特例,并且可能会随着对现实应用程序的每一次更改而崩溃。

关于java - ConcurrentMap.remove() 是否在 get() 返回 null 之前提供先行边?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39341742/

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