Some background:
When a collection is iterated using Iterator
then there could java.util.ConcurrentModificationException
because under the hoods when the Iterator
object is created then the modification count (modCount
) of the collection or ArrayList is captured and on each iteration using Iterator.next()
it is checked if modCount
has changed, if so then throw java.util.ConcurrentModificationException
.
On creating iterator object (from ArrayList
's Iterator
implementation):
int expectedModCount = modCount;
Below method gets called upon Iterator.next()
, which throws exception (from ArrayList
's Iterator
implementation):
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
I could very well reproduce it using below code:
List<String> stringList = new ArrayList<String>();
stringList.add("a");
stringList.add("b");
stringList.add("c");
Iterator<String> iterator = stringList.iterator();
System.out.println("Got iterator object");
while (iterator.hasNext()) {
String player = iterator.next();
player.toString();
System.out.println("UpperCase: " + player.toUpperCase());
iterator.remove();
stringList.add("a1"); //This is root cause of exception.
}
Question:
- If I try to modify the list using a different thread (code is below) then I do not get
java.util.ConcurrentModificationException
but if I do using same thread then I get the exception.
If I understand correct then still on each pass of Iterator.next()
from first thread, Iterator.checkForComodification()
will be called internally, and since my second thread has modified the list, so latest modCount
will not be equal Iterator.expectedModCount
which was initialized when Iterator
object was created, hence exception should have occurred from Iterator.checkForComodification()
. Right?
I have verified that list is getting updated from thread 2 and iterator from thread 1 is able to print the new value, because I can see the "d" value printed which is being added by second thread.
private static void iteratorException() {
final List<String> stringList = new ArrayList<String>();
Thread thread = new Thread(){
@Override
public void run() {
System.out.println("T1");
stringList.add("a");
stringList.add("b");
stringList.add("c");
Iterator<String> iterator = stringList.iterator();
System.out.println("Got iterator object");
while (iterator.hasNext()) {
String player = iterator.next();
player.toString();
System.out.println("UpperCase: " + player.toUpperCase());
iterator.remove();
//stringList.add("a1");
}
}
};
Thread thread2 = new Thread(){
@Override
public void run() {
System.out.println("T2");
stringList.add("d");
stringList.remove("a");
System.out.println("finished T2");
}
};
thread.start();
thread2.start();
}