Почему параллельная модификация приходит сюда - PullRequest
0 голосов
/ 20 декабря 2018

Следующий код выдает исключение одновременной модификации

import java.util.*;

public class SampleTest
{
public static void main(String[] args) {

    LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
    map.put("value1","a");
    map.put("value2","b");
    map.put("value3","c");
    map.put("value4","d");
    map.put("value5","e");

    // sublists
    List<LinkedHashMap<String, String>> subList = new ArrayList<>();
    for(int i = 0; i<5; i++) {
        subList.add(map);
    }

    List<List<LinkedHashMap<String, String>>> mainList = new LinkedList<>();
    for(int i = 0; i<3; i++)
    {
        mainList.add(subList);
    }

    List<LinkedHashMap<String,String>> temp =  mainList.get(mainList.size() - 1);
    List<LinkedHashMap<String,String>> temp2 =  mainList.get(mainList.size() - 2);
    for(LinkedHashMap<String,String> map2 : temp) {
        temp2.add(map); // Exception Thrown Here......
    }
}
}

Однако я исправил код, создав новый список, добавив карту и, наконец, добавив новый список вне цикла в temp2

example,
    List<LinkedHashMap<String,String>> pp = new ArrayList<>();
    for(LinkedHashMap<String,String> map2 : temp) {
       pp.add(map);
    }
    temp2.addAll(pp);

Я хотел бы подробно узнать, почему параллелизм происходит в более раннем коде.

Спасибо.

1 Ответ

0 голосов
/ 28 декабря 2018

Этот код:

List<List<LinkedHashMap<String, String>>> mainList = new LinkedList<>();
for(int i = 0; i<3; i++)
{
    mainList.add(subList);
}

Добавляет subList три раза к mainList.Когда я говорю «три раза», я имею в виду, что код буквально добавляет один и тот же экземпляр три раза.Вы можете изменить элемент с любым допустимым индексом mainList, и вы изменили бы все остальные элементы, потому что это один и тот же экземпляр.См. этот вопрос ;это может помочь с этой концепцией.

Как следствие, этот код:

List<LinkedHashMap<String,String>> temp =  mainList.get(mainList.size() - 1);
List<LinkedHashMap<String,String>> temp2 =  mainList.get(mainList.size() - 2);

Извлекает то же самое List из двух разных индексов и присваивает его двум различным переменным.Другими словами, temp == temp2 (равенство ссылок) равно true.

Затем вы повторяете List, используя переменную temp, в то же время добавляя элементы в List, используяпеременная temp2:

for(LinkedHashMap<String,String> map2 : temp) {
    temp2.add(map); // Exception Thrown Here......
}

Но, опять же, temp и temp2 относятся к то же List.Ваш код в основном делает следующее:

List<Object> list = ...; // create new list and fill it
Object someObj = new Object();

for (Object obj : list) { // iterating list
    list.add(someObj); // modifying list while it's being iterated
}

Конечный результат - вы итерируете List, пытаясь изменить его одновременно.Это не допускается LinkedList (или вообще любой из стандартных реализаций Collection).Из документации :

Итераторы, возвращаемые методами iterator и listIterator этого класса, fail-fast : если список структурно измененв любое время после создания итератора, любым способом, кроме использования собственных методов итератора remove или add, итератор выдаст исключение ConcurrentModificationException .Таким образом, перед лицом одновременной модификации, итератор быстро и чисто дает сбой, вместо того, чтобы рисковать произвольным недетерминированным поведением в неопределенное время в будущем.

Если вы не знаете,цикл for-each внутренне использует Iterator, когда целью цикла является Iterable.

...