为什么同时进行修改

时间:2018-12-20 01:38:02

标签: java exception linkedhashmap concurrentmodification

以下代码引发并发修改异常

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 :(得分:1)

此代码:

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

正在subList中添加mainList三次。当我说“三遍”时,我的意思是代码将同一实例添加了三遍。您可以在mainList的任何有效索引处修改元素,并且将修改所有其他元素,因为它们是同一实例。参见this question;这可能对这个概念有所帮助。

因此,此代码:

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

但是,temptemp2同样是指相同 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的任何标准实现)都不允许这样做。来自documentation

  

此类的iteratorlistIterator方法返回的迭代器是 fail-fast :如果在创建迭代器后的任何时间对列表进行结构修改,除了通过迭代器自己的removeadd方法之外,迭代器将抛出ConcurrentModificationException。因此,面对并发修改,迭代器会快速干净地失败,而不会在未来的不确定时间内冒任意,不确定的行为的风险。

如果您不知道,则循环的目标是Iterator时,for-each循环会在内部使用Iterable