【问题标题】:java - iterator.remove() if set is modified while iterationjava - iterator.remove() 如果在迭代时修改了 set
【发布时间】:2014-02-23 21:55:38
【问题描述】:

我有一个被许多线程不断扩展的 Set:

Set<String> concurrentSet = new CopyOnWriteArraySet<>();

有时我会处理集合中的元素,因为我不再需要处理过的元素,所以我使用 iterator.remove() 删除它们:

Iterator<String> i = concurrentSet .iterator();
while (i.hasNext()) {
    String str = i.next();
    //processing...
    i.remove();
}

这是线程安全的吗?如果线程在迭代时添加元素怎么办?

注意:doc 声明“如果在迭代过程中通过调用此方法以外的任何方式修改了基础集合,则迭代器的行为是未指定的。” => CopyOnWriteArraySet 也是这样吗?

【问题讨论】:

  • 什么是ConcurrentHashSet?它不是 jdk 的一部分...
  • 感谢评论,我改成了jdk提供的线程安全集实现
  • 这不是一个很好的例子:“迭代器不支持可变删除操作。”!

标签: java multithreading concurrency iterator set


【解决方案1】:

我认为这适用于集合不是线程安全的情况。 ConcurrentHashset 是为了处理这种情况而添加的。

【讨论】:

    【解决方案2】:

    这取决于您使用的线程安全实现。例如:

    • CopyOnWriteArraySet javadoc 声明:“迭代器不支持可变删除操作。” => 如果您调用 it.remove(),您将收到异常。
    • ConcurrenSkipListSet javadoc 声明:“插入、删除和访问操作可以安全地由多个线程并发执行。迭代器是弱一致的,返回的元素反映了在迭代器创建时或之后的某个时间点的集合状态。" => 你可以放心地假设调用 it.remove() 是线程安全的(因为它不会抛出 ConcurrentModificationException)。

    但请注意:

    if (it.hasNext()) {
        it.next();
        it.remove();
    }
    

    不是原子的,因此如果同时修改集合,该操作的结果可能会出乎意料。

    【讨论】:

      【解决方案3】:

      CopyOnWriteArraySet 是线程安全的,但Iterators 不支持可变删除操作,您可以使用CopyOnWriteArraySet#remove 删除 ovject 但对这个数据结构的操作很昂贵,因为所有可变操作(添加、设置、删除等) .) 非常昂贵,因为此操作完全复制了整个底层数组。

      Find more on documentaton.

      【讨论】:

        【解决方案4】:

        来自 Java 7 JavaDoc (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CopyOnWriteArraySet.html):

        [CopyOnWriteArraySet] 迭代器不支持可变删除操作。

        如果线程安全比性能更重要,我建议使用类似于 Collections.synchronizedSet 的东西。它更难使用,您必须在 synchronized(set) {} 块中使用迭代器显式包装代码,但您可以保证所有操作都是线程安全的。

        如果需要同时并发和线程安全,那么您可以通过 ReentrantReadWriteLock 使用带有您自己的显式锁定的普通 HashSet。如果正确实施,这将允许读取并发和写入线程安全。我不知道 Java API 中有一个标准类,但那里可能有一个(或者确实在其他地方,例如 Apache Commons Collections)。

        【讨论】:

        • 我还不能评论其他人的帖子,但有一条评论提到了 ConcurrentSkipListSet - 这是一个很好的选择,只要 Set 中的所有元素都实现 Comparable 接口或提供自定义 Comparator集合创建,因为它扩展了 SortedSet 接口。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-03-26
        • 2018-10-08
        • 1970-01-01
        • 1970-01-01
        • 2012-03-03
        • 2012-11-21
        • 2023-03-13
        相关资源
        最近更新 更多