Почему нет ConcurrentModificationException, когда один поток повторяется (используя Iterator), а другой поток изменяет одну и ту же копию не-поточно-безопасного ArrayList

Немного предыстории:
Когда коллекция повторяется с использованием Iterator тогда мог java.util.ConcurrentModificationException потому что под капотами, когда Iterator объект создается, то счетчик модификаций (modCount) коллекции или ArrayList захватывается и на каждой итерации, используя Iterator.next() проверяется, если modCount изменилось, если так то киньте java.util.ConcurrentModificationException,

При создании объекта итератора (из ArrayList "s Iterator реализация):
int expectedModCount = modCount;

Ниже метод вызывается Iterator.next(), который выдает исключение (из ArrayList "s Iterator реализация):

final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

Я мог бы очень хорошо воспроизвести это, используя следующий код:

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.
                }

Вопрос:

  • Если я пытаюсь изменить список, используя другой поток (код ниже), то я не получаю java.util.ConcurrentModificationException но если я использую тот же поток, я получаю исключение.

Если я правильно понимаю, то еще на каждом проходе Iterator.next() из первого потока, Iterator.checkForComodification() будет вызываться изнутри, и так как мой второй поток изменил список, последний modCount не будет равных Iterator.expectedModCount который был инициализирован, когда Iterator объект был создан, следовательно, исключение должно было произойти из Iterator.checkForComodification(), Правильно?

Я убедился, что список обновляется из потока 2, а итератор из потока 1 может напечатать новое значение, потому что я вижу напечатанное значение "d", которое добавляется вторым потоком.

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

0 ответов

Другие вопросы по тегам