gpt4 book ai didi

java - ConcurrentHashMap 中 entrySet().removeIf 的行为

转载 作者:太空狗 更新时间:2023-10-29 22:40:27 27 4
gpt4 key购买 nike

我想使用 ConcurrentHashMap 让一个线程定期从 map 中删除一些项目,同时让其他线程从 map 中放置和获取项目。

我在删除线程中使用 map.entrySet().removeIf(lambda)。我想知道我可以对其行为做出哪些假设。我可以看到 removeIf 方法使用迭代器遍历映射中的元素,检查给定条件,然后在需要时使用 iterator.remove() 删除它们。

文档提供了一些关于 ConcurrentHashMap 迭代器行为的信息:

Similarly, Iterators, Spliterators and Enumerations return elements reflecting the state of the hash table at some point at or since the creation of the iterator/enumeration. hey do not throw ConcurrentModificationException. However, iterators are designed to be used by only one thread at a time.

由于整个 removeIf 调用发生在一个线程中,因此我可以确定迭代器不会同时被多个线程使用。我仍然想知道下面描述的事件过程是否可能:

  1. Map 包含映射:'A'->0
  2. 删除线程开始执行map.entrySet().removeIf(entry->entry.getValue()==0)
  3. 删除线程在 removeIf 调用中调用 .iteratator() 并获取反射(reflect)集合当前状态的迭代器
  4. 另一个线程执行map.put('A', 1)
  5. 删除线程仍然看到 'A'->0 映射(迭代器反射(reflect)旧状态)并且因为 0==0 为真,它决定从中删除 A 键 map 。
  6. map 现在包含 'A'->1 但删除线程看到旧值 0'A' ->1 条目被删除,即使它不应该被删除。 map 是空的。

我可以想象,这种行为可能会被实现以多种方式阻止。例如:迭代器可能不反射(reflect)放置/删除操作,但始终反射(reflect)值更新,或者迭代器的删除方法可能在调用键上的删除之前检查整个映射(键和值)是否仍然存在于映射中。我找不到有关发生的任何事情的信息,我想知道是否有什么东西可以使该用例安全。

最佳答案

我也设法在我的机器上重现了这种情况。我认为,问题是 EntrySetView(由 ConcurrentHashMap.entrySet() 返回)从 Collection< 继承了它的 removeIf 实现,它看起来像:

    default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
// `test` returns `true` for some entry
if (filter.test(each.next())) {
// entry has been just changed, `test` would return `false` now
each.remove(); // ...but we still remove
removed = true;
}
}
return removed;
}

以我的拙见,这不能被视为 ConcurrentHashMap 的正确实现。

关于java - ConcurrentHashMap 中 entrySet().removeIf 的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29876083/

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