In this Q&A, we'll go over what's a concurrent modification exception and two solutions to avoid it.
When would the exception be thrown
ConcurrentModificationException is thrown when the iterator is invalidated by a collection mutating operation.
In the example below, adding an element to list invalidates the iterator. Iterator.next() operation would then throw an exception.
In the example below, adding an element to list invalidates the iterator. Iterator.next() operation would then throw an exception.
Please note that iterator invalidation can happen in the same thread. Two threads are not required.
public static void simulateConcurrentModification() throws ConcurrentModificationException {
List<Integer> l = new ArrayList<>();
for(int i=0; i < 1000; ++i) {
l.add(i);
}
Iterator<Integer> li = l.iterator();
while(li.hasNext()) {
Integer i = li.next();
if( i <= 200 && i >= 100 )
l.add(i);
}
}
Would synchronizing the collection prevent ConcurrentModificationException
Purpose of synchronizing the collection is to allow thread safe read/write operations to the list. It does NOT prevent ConcurrentModificationException.
Function below still throws ConcurrentModificationException
public static void simulateConcurrentModification2() {
List<Integer> l = new ArrayList<>();
for(int i=0; i < 1000; ++i) {
l.add(i);
}
List<Integer> l2 = Collections.synchronizedList(l);
Iterator<Integer> li = l2.iterator();
while(li.hasNext()) {
Integer i = li.next();
if( i <= 200 && i >= 100 )
l2.remove(i);
}
}
Avoiding the exception - Solution I
If its required to add or remove an element while iterating over it, then use iterator.add or iterator remove methods. This is illustrated in the example belowpublic static void fixConcurrentModification() {
List<Integer> l = new ArrayList<>();
for(int i=0; i < 1000; ++i) {
l.add(i);
}
ListIterator<Integer> li = l.listIterator();
while(li.hasNext()) {
Integer i = li.next();
if( i <= 200 && i >= 100 )
li.add(i);
}
}
Avoiding the exception - Solution II
Adding/removing elements via an iterator does not invalidate the iterator. But it will invalidate another iterator on the same collection.
This can be solved by using CopyonWrite list classes. See example below.
public static void fixConcurrentModification2() {
List<Integer> l = new CopyOnWriteArrayList<>();
for(int i=0; i < 1000; ++i) {
l.add(i);
}
ListIterator<Integer> li = l.listIterator();
while(li.hasNext()) {
Integer i = li.next();
if( i <= 200 && i >= 100 )
l.add(i);
}
}
Comments
Post a Comment