【发布时间】:2020-07-09 20:40:15
【问题描述】:
假设我们有一个类 Container
class Container {
private final Map<LongHolder, Integer> map = new ConcurrentHashMap<>();
static class LongHolder {
private final Long i;
private LongHolder(Long i) {
this.i = i;
}
}
public LongHolder createValue(Long i) {
LongHolder v = new LongHolder(i);
map.put(v, 1)
return LongHolder;
}
public void doSmth(LongHolder longHolder) {
map.get(longHolder);
... // do smth
}
}
是否可以以这样的方式对操作进行重新排序,即从 createValue 对 LongHolder 的引用会转义该方法,从而在将其放入映射之前对其他线程可用?在这种情况下,我们可以获取 LongHolder 引用表单 createValue 并将其传递给在地图中看不到的另一个线程中的 doSmth。可能吗?如果不是请解释一下。
更新:
ConcurrentHashMap 的 Javadoc 状态 Retrievals 反映了最近完成的更新操作的结果。
发作。 (更正式地说,给定密钥的更新操作带有
与任何(非空)检索的发生之前的关系
该键报告更新的值。)
但是有最近完成的更新操作
重新排序时的问题正是关于这种微妙的情况
可能会以实际更新操作的方式发生
在put.The Javadoc 之前未完成并且引用已转义
ConcurrentHashMap 仅说明 给定密钥具有
与该键的任何(非空)检索发生之前的关系
换句话说,只有当我们检索到那个键时,我们才能辩论
关于发生在与此键的更新操作的关系。
我只能提出一些其他无法实现的原因:
1) 重新排序规则比我想象的更严格,我们不能假设仲裁重新排序(或者我们可以吗?规则是什么?)。
2) put 具有一些不允许重新编码的神奇属性,而 return 仅在完成 put 后才会发生。在这种情况下,这些属性是什么?
【问题讨论】:
-
不,这是不可能的。
ConcurrentHashMap保证 Happens-before relationship。所以,只要put发生在get之前,就会得到一致的结果。 -
你如何想象它“逃脱了方法”?它在那里创建然后返回;除了
createValue的结果,即在它已经放入地图之后,另一段代码如何访问它? -
在没有适当同步的情况下,在对象构造过程中也会发生同样的情况。
标签: java concurrency java.util.concurrent