Why no ConcurrentModificationException when one th

2019-06-11 17:21发布

问题:

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();
}