java - iterator.remove()如果在迭代时修改了set

时间:2014-01-31 09:10:49

标签: java multithreading concurrency iterator set

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

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

在某些时候我处理集合的元素,因为我不再需要处理过的元素,我使用iterator.remove()删除它们:

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

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

注意:doc表示“如果在迭代正在进行的过程中修改基础集合而不是通过调用此方法,则未指定迭代器的行为。” =&GT;这对CopyOnWriteArraySet也是如此吗?

4 个答案:

答案 0 :(得分:0)

我认为这适用于集合不是线程安全的情况。 ConcurrentHashset旨在被添加来处理这种情况..

答案 1 :(得分:0)

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

  • CopyOnWriteArraySet javadoc声明:“迭代器不支持变异删除操作。”=&gt;如果致电it.remove(),您将收到例外情况。
  • ConcurrenSkipListSet javadoc声明:“插入,删除和访问操作由多个线程安全地同时执行。迭代器是弱一致的,返回元素反映集合的某个时刻或创建时的状态迭代器。“=&gt;你可以放心地假设调用it.remove()是线程安全的(因为它不会抛出ConcurrentModificationException)。

但请注意:

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

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

答案 2 :(得分:0)

CopyOnWriteArraySet是线程安全的但是Iterators不支持mutative remove操作,你可以使用CopyOnWriteArraySet#remove删除ovject但是对这个数据结构的操作是昂贵的,因为所有的mutiable操作(添加由于此操作完全复制整个底层阵列,因此设置,删除等都很昂贵。

Find more on documentaton

答案 3 :(得分:0)

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

[CopyOnWriteArraySet]迭代器不支持mutative remove操作。

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

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