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

标签 java multithreading java.util.concurrent concurrenthashmap concurrentmodification

我想使用 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/

相关文章:

java - 没有反向关系的多态 CriteriaQuery

c# - 多线程设计模式

python - 拆分 Django 项目

Java ScheduledExecutorService 生产者\消费者

java - 使用自定义 RejectedExecutionHandler

java - android ArrayMap 抛出 java.lang.ClassCastException : java. lang.String 无法转换为 java.lang.Object[]

java - JPA:OneToOne 关系所有者

java - Scala Map 和 ConcurrentHashMap 抛出 java.lang.UnsupportedOperationException

Java 服务器基本计算器

c++ - 尝试等待 boost::condition_Variable 时出现 "unique_lock has no mutex: Operation not permitted"错误