繁体   English   中英

ConcurrentHashMap.keySet().stream() 的一致性行为

[英]Consistency behaviour of ConcurrentHashMap.keySet().stream()

我可以从这个带有ConcurrentHashMapmodify方法中获得什么一致性行为?

// 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引用)提到:

它们[即迭代器和拆分器]保证遍历元素,因为它们在构造时就存在一次,并且可能(但不保证)反映构造后的任何修改。

ConcurrentHashMapTraverser 的 javadoc (迭代器和拆分器的基本 class)中也提到了它:

封装了对 containsValue 等方法的遍历; 还用作其他迭代器和拆分器的基础 class。

方法提前访问一次在迭代器构造时可到达的每个仍然有效的节点。 它可能会错过一些在访问 bin 后添加到 bin 中的内容,这可以保证一致性。

“过去的某个时间点”也很模糊:您看不到在创建stream()之前从 map 中删除的密钥。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM