简体   繁体   English

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

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

What consistency behaviour can I expect from this modify method with a ConcurrentHashMap ?我可以从这个带有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);
      }
    });
}

I find it difficult to get a definitive answer from reading the Javadocs, how keySet() , stream() , and modification of the map entry inside the stream interact together.我发现通过阅读 Javadocs 很难得到明确的答案, keySet()stream()和 stream 中的 map 条目的修改如何相互作用。 I know that keySet() 's spliterator is weakly consistent , so the stream should at least iterate through all the elements, as they were present at some point in the past, only once.我知道keySet()的分离器是弱一致的,所以spliterator至少应该遍历所有元素,因为它们在过去的某个时候只存在一次。 And that modifying the data source during stream execution is supported for concurrent collections (see Non-interference ).并发 collections 支持在 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ 执行期间修改数据源(请参阅非干扰)。 It might be relevant that I am always modifying the current key only and not touching other map entries in the foreach lambda.我总是只修改当前密钥而不触及foreach lambda 中的其他 map 条目,这可能是相关的。

So is the above code "all good" in a weakly consistent manner, or are there some caveats which I should be aware of?那么上面的代码是以弱一致的方式“都很好”,还是有一些我应该注意的警告?


Note: The above code also doesn't make really sense like that, but this is simplified code with other non-concurrency-related aspects left out.注意:上面的代码也没有真正的意义,但这是简化的代码,省略了其他与并发相关的方面。

It's possible that the code can be written better using different methods, eg forEach on the map itself.使用不同的方法可以更好地编写代码,例如 map 本身的forEach Feel free to suggest improvements if it adds to the answer, but please provide only answers that answer my actual question.如果它增加了答案,请随时提出改进建议,但请仅提供回答我实际问题的答案。 I am not asking how to make this better, I am merely wondering how all the parts interact in my example.我不是在问如何让它变得更好,我只是想知道在我的示例中所有部分如何交互。

the stream should at least iterate through all the elements, as they were present at some point in the past, only once stream 至少应该遍历所有元素,因为它们在过去的某个时候只存在一次

I would remove "all" from the phrase, because this wording might give a false impression that the stream iterates over some atomic snapshot of the whole ConcurrentHashMap .我会从短语中删除“全部”,因为这个措辞可能会给人一种错误的印象,即 stream 会迭代整个ConcurrentHashMap的一些原子快照。
In reality the stream might reflect (some) modifications of the map, which happened after the stream was created.实际上,stream 可能反映了 map 的(一些)修改,这些修改发生在 stream 创建之后。 As a result, it is possible that the first and the last keys emitted by a stream have never been in the map at the same time.因此,ZF7B44CFFAFD5C52223D5498196C8A2E7BZ 发出的第一个和最后一个密钥可能从未同时出现在 map 中。

The wording for weakly consistent (referenced by the keySet()'s javadoc ) mentions that: 弱一致的措辞(由keySet() 的 javadoc引用)提到:

they [ie Iterators and Spliterators] are guaranteed to traverse elements as they existed upon construction exactly once, and may (but are not guaranteed to) reflect any modifications subsequent to construction.它们[即迭代器和拆分器]保证遍历元素,因为它们在构造时就存在一次,并且可能(但不保证)反映构造后的任何修改。

It is also mentioned in another words in the javadoc for Traverser (the base class for iterators and spliterators) in ConcurrentHashMap :ConcurrentHashMapTraverser 的 javadoc (迭代器和拆分器的基本 class)中也提到了它:

Encapsulates traversal for methods such as containsValue;封装了对 containsValue 等方法的遍历; also serves as a base class for other iterators and spliterators.还用作其他迭代器和拆分器的基础 class。

Method advance visits once each still-valid node that was reachable upon iterator construction.方法提前访问一次在迭代器构造时可到达的每个仍然有效的节点。 It might miss some that were added to a bin after the bin was visited, which is OK wrt consistency guarantees.它可能会错过一些在访问 bin 后添加到 bin 中的内容,这可以保证一致性。

Also "some point in the past" is pretty vague as well: you cannot see a key which was removed from the map before the stream() was created. “过去的某个时间点”也很模糊:您看不到在创建stream()之前从 map 中删除的密钥。

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

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