Why no ConcurrentModificationException when one thread iterating (using Iterator) and other thread modifying same copy of non-thread-safe ArrayList

断了今生、忘了曾经 提交于 2019-12-23 04:45:55

问题


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

来源:https://stackoverflow.com/questions/31372131/why-no-concurrentmodificationexception-when-one-thread-iterating-using-iterator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!