简体   繁体   English

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

[英]java - iterator.remove() if set is modified while iteration

I have a Set that is continuously extended by many threads: 我有一个由多个线程连续扩展的Set:

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

At some point I process the elements of the set, and since I don't need the processed elements anymore, I remove them using iterator.remove(): 有时我会处理集合中的元素,由于不再需要已处理的元素,因此可以使用iterator.remove()删除它们:

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

Is this threadsafe? 这是线程安全的吗? what if a thread adds elements while iterating? 如果线程在迭代时添加元素怎么办?

note: the doc states that "The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method." 注意: 文档指出“如果在迭代进行过程中以其他方式(而不是通过调用此方法)修改基础集合,则未指定迭代器的行为。” => is this true for the CopyOnWriteArraySet too? => CopyOnWriteArraySet也是如此吗?

I think this applies to the cases where the collection is not threadsafe. 我认为这适用于集合不是线程安全的情况。 ConcurrentHashset was meant to be added to handle such situations.. 本来应该添加ConcurrentHashset来处理这种情况。

It depends on which thread safe implementation you use. 这取决于您使用的线程安全实现。 For example: 例如:

  • CopyOnWriteArraySet javadoc states: " Iterators do not support the mutative remove operation. " => you will get an exception if you call it.remove() . CopyOnWriteArraySet javadoc指出:“ 迭代器不支持可变的remove操作。 ” =>如果调用it.remove()则会出现异常。
  • ConcurrenSkipListSet javadoc states: " Insertion, removal, and access operations safely execute concurrently by multiple threads. Iterators are weakly consistent, returning elements reflecting the state of the set at some point at or since the creation of the iterator. " => you can safely assume that calling it.remove() is thread safe (as in it won't throw a ConcurrentModificationException). ConcurrenSkipListSet javadoc状态:“ 插入,删除和访问操作可以安全地由多个线程同时执行。迭代器是弱一致性的,在创建迭代器时或创建迭代器后的某个时刻返回反映集合状态的元素。 ” =>您可以放心假设调用it.remove()是线程安全的(因为它不会引发ConcurrentModificationException)。

Note however that: 但是请注意:

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

is not atomic, so the result of that operation can be unexpected if the set is modified concurrently. 不是原子的,因此如果同时修改集合,该操作的结果可能是意外的。

CopyOnWriteArraySet is thread-safe but Iterators do not support the mutative remove operation, you can use CopyOnWriteArraySet#remove to remove ovject but operation on this datastructure is expensive as all mutative operations (add, set, remove, etc.) are expensive due to this operation wholly copying the entire underlying array. CopyOnWriteArraySet是线程安全的,但是Iterators不支持可变删除操作,您可以使用CopyOnWriteArraySet#remove删除ovject,但由于所有此可变操作(添加,设置,删除等)都非常昂贵,因此对该数据结构的操作非常昂贵操作完全复制整个基础数组。

Find more on documentaton . 在documentaton上找到更多信息

From the Java 7 JavaDoc ( http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CopyOnWriteArraySet.html ): 从Java 7 JavaDoc( http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CopyOnWriteArraySet.html ):

[CopyOnWriteArraySet] Iterators do not support the mutative remove operation. [CopyOnWriteArraySet]迭代器不支持可变删除操作。

If thread safety if of higher importance than performance, I would advise using something along the lines of Collections.synchronizedSet. 如果线程安全比性能更重要,我建议您沿Collections.synchronizedSet的方式使用。 It's harder to use and you have to explicitly wrap code using iterators in a synchronized(set) {} block but you can guarantee that all operations are thread safe. 使用起来比较困难,您必须使用迭代器将代码显式地包装在synceded(set){}块中,但是可以保证所有操作都是线程安全的。

If simultaneous concurrency and thread safety are required then you could use a normal HashSet with your own explicit locking via a ReentrantReadWriteLock. 如果需要同时进行并发和线程安全,则可以通过ReentrantReadWriteLock将普通的HashSet与自己的显式锁定一起使用。 This would allow read concurrency and write thread safety if implemented correctly. 如果正确实现,这将允许读取并发和写入线程安全。 I'm not aware of a standard class for this in the Java API, but there may be one there (or indeed elsewhere, such as Apache Commons Collections). 我不知道Java API中有一个与此相关的标准类,但是那里可能有一个(或者实际上在其他地方,例如Apache Commons Collections)。

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

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