Java - 线程“main”java.util.ConcurrentModificationException中的异常

时间:2014-10-17 05:16:41

标签: java collections concurrency hashmap concurrentmodification

有什么办法可以在迭代时修改特定键的HashMap值吗?

示例程序如下:

public static void main(String[] args) {
    HashMap<Integer,ArrayList<String>> hm = new HashMap<Integer, ArrayList<String>>();      
    ArrayList<String> ar = new ArrayList<String>(); 
    for(int i=0;i<50;i++){              
        ar.add(Integer.toString(i));            
    }

    hm.put(1, ar);      

    for(String s:hm.get(1)){
        hm.get(1).add("hello");
    }

}

错误抛出:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at Excp.main(Excp.java:17)

8 个答案:

答案 0 :(得分:2)

当我们尝试在迭代时修改集合对象时,我们会得到此异常。请检查以下代码:

for(String str : stringList){ 
   stringList.add("Test");
}

所以在上面我们得到运行时异常。

解决方案

在For-Each循环上使用迭代器,例如:

static void filter(Collection<?> c) {
    for (Iterator<?> it = c.iterator(); it.hasNext(); )
       if (!anyCondition(it.next()))
          it.remove();
}

For-Each和iterator之间的基本区别是,我们可以在仅使用迭代器进行迭代时修改集合。

答案 1 :(得分:1)

当不允许进行此类修改时,检测到对象的并发修改的方法可能抛出此异常。

下面的代码导致了问题。

for(String s:hm.get(1)){
        hm.get(1).add("hello");
    }

您正在迭代并修改它。通过创建new ArrayList

来避免这种情况
  ArrayList<String> ar1 = new ArrayList<String>();

for (String s : hm.get(1)) {
            ar1.add("hello");
        }

阅读here

答案 2 :(得分:1)

您所呈现的代码中的问题不是修改HashMap,而是在迭代它时修改ArrayList。 如果您使用ar&#39; ListIterator而不是使用增强型for循环,则可以避免此异常:

for (ListIterator<String> i = ar.listIterator(); i.hasNext(); i.next()) {
    i.add("hello");
} 

答案 3 :(得分:0)

如果在迭代列表时尝试修改,您将获得此Exception

for(String s:hm.get(1)){ // iterate 
    hm.get(1).add("hello");//modify
}

这两项操作都会影响hm

您无需在此处进行迭代。只需使用

hm.get(1).add("hello");

答案 4 :(得分:0)

如果您要添加到原始 ArrayList,请自行迭代:

final ArrayList<String> arr = hm.get(1);
final int size = arr.size();

// this will add size number of "hello" strings to ArrayList arr
for(int i = 0; i < size; ++i){
    // you don't appear to ever use this value
    final String s = arr.get(i);

    // do something to arr
    arr.add("hello");
}

答案 5 :(得分:0)

虽然与问题无关,但只是添加

如果首先在集合上获取迭代器,然后在其上添加更多元素,然后迭代集合将抛出此异常,也会发生ConcurrentModificationException。

例如:

package got;

import java.util.*;

public class GotCharacters {


    public static void main(String... args){

        Person p1 = new Person("TL", 40, "Tyrion Lannister");
        Person p2 = new Person("JM", 50, "Jorah Mormont");
        Person p3 = new Person("AS", 20, "Arya Stark");

        //Defining the collection and adding some elements
        ArrayList<Person> al;
        al = new ArrayList<Person>();
        al.add(p1);
        al.add(p2);
        al.add(p3);

        //Getting the iterator
        Iterator<Person> itr = al.iterator();

        Royalty r1 = new Student("DT", 25, "Daenerys Targaryen", "DragonMother", "Targaryen");
        Royalty r2 = new Student("JS", 28, "Jon Snow", "Lord Commander", "Targaryen");
        Collection<Royalty> c = new ArrayList<Royalty>();
        c.add(s1);
        c.add(s2);

        //Adding more elements after getting the iterator
        al.addAll(c);

        while(itr.hasNext()){
            System.out.print(itr.next());
        }
    }
}

结果:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
    at java.util.ArrayList$Itr.next(ArrayList.java:851)
    at myArrayList.ArrayList1.main(ArrayList1.java:34)

答案 6 :(得分:0)

编程中的并发修改是指在另一个任务已经在其上运行时同时对其进行修改。 Java中的快速失败和安全失败迭代器 Java中的迭代器用于迭代Collection对象。如果对集合进行了结构修改,则快速失败迭代器会立即引发 ConcurrentModificationException 。如果在迭代集合时对其结构进行了修改,则故障保护迭代器不会引发任何异常。这是因为它们在集合的克隆上而不是原始集合上进行操作,因此将其称为故障保护迭代器。 如果要在两者之间进行修改,请使用ConcurrentHashMap。

答案 7 :(得分:0)

如果您可以使用普通(迭代索引)for 循环,则可以避免该错误。