简体   繁体   中英

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

I have a Set that is continuously extended by many threads:

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<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?

I think this applies to the cases where the collection is not threadsafe. ConcurrentHashset was meant to be added to handle such situations..

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() .
  • 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).

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.

Find more on documentaton .

From the 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.

If thread safety if of higher importance than performance, I would advise using something along the lines of 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.

If simultaneous concurrency and thread safety are required then you could use a normal HashSet with your own explicit locking via a ReentrantReadWriteLock. 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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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