[英]Consistency behaviour of ConcurrentHashMap.keySet().stream()
我可以从这个带有ConcurrentHashMap
的modify
方法中获得什么一致性行为?
// map is filled concurrently from multiple threads
private final ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();
public void modify(Object newValue) {
map.keySet().stream()
.filter(/* some filter */)
.forEach(k -> {
if (/* k has some property */) {
map.put(k, newValue);
} else {
map.remove(k);
}
});
}
我发现通过阅读 Javadocs 很难得到明确的答案, keySet()
、 stream()
和 stream 中的 map 条目的修改如何相互作用。 我知道keySet()
的分离器是弱一致的,所以spliterator
至少应该遍历所有元素,因为它们在过去的某个时候只存在一次。 并发 collections 支持在 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ 执行期间修改数据源(请参阅非干扰)。 我总是只修改当前密钥而不触及foreach
lambda 中的其他 map 条目,这可能是相关的。
那么上面的代码是以弱一致的方式“都很好”,还是有一些我应该注意的警告?
注意:上面的代码也没有真正的意义,但这是简化的代码,省略了其他与并发相关的方面。
使用不同的方法可以更好地编写代码,例如 map 本身的forEach
。 如果它增加了答案,请随时提出改进建议,但请仅提供回答我实际问题的答案。 我不是在问如何让它变得更好,我只是想知道在我的示例中所有部分如何交互。
stream 至少应该遍历所有元素,因为它们在过去的某个时候只存在一次
我会从短语中删除“全部”,因为这个措辞可能会给人一种错误的印象,即 stream 会迭代整个ConcurrentHashMap
的一些原子快照。
实际上,stream 可能反映了 map 的(一些)修改,这些修改发生在 stream 创建之后。 因此,ZF7B44CFFAFD5C52223D5498196C8A2E7BZ 发出的第一个和最后一个密钥可能从未同时出现在 map 中。
弱一致的措辞(由keySet() 的 javadoc引用)提到:
它们[即迭代器和拆分器]保证遍历元素,因为它们在构造时就存在一次,并且可能(但不保证)反映构造后的任何修改。
在ConcurrentHashMap
的Traverser
的 javadoc (迭代器和拆分器的基本 class)中也提到了它:
封装了对 containsValue 等方法的遍历; 还用作其他迭代器和拆分器的基础 class。
方法提前访问一次在迭代器构造时可到达的每个仍然有效的节点。 它可能会错过一些在访问 bin 后添加到 bin 中的内容,这可以保证一致性。
“过去的某个时间点”也很模糊:您看不到在创建stream()
之前从 map 中删除的密钥。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.