Java 并发修改异常

Java 并发修改异常,java,concurrentmodification,Java,Concurrentmodification,我有这段代码,它给了我并发修改异常。我不明白为什么我一直得到它,即使我没有看到任何并发的修改正在进行 import java.util.*; public class SomeClass { public static void main(String[] args) { List<String> s = new ArrayList<>(); ListIterator<String> it = s.listIterat

我有这段代码,它给了我并发修改异常。我不明白为什么我一直得到它,即使我没有看到任何并发的修改正在进行

import java.util.*;

public class SomeClass {
    public static void main(String[] args) {
        List<String> s = new ArrayList<>();
        ListIterator<String> it = s.listIterator();

        for (String a : args)
            s.add(a);

        if (it.hasNext())
            String item = it.next();

        System.out.println(s);
    }
}
import java.util.*;
公共类{
公共静态void main(字符串[]args){
列表s=新的ArrayList();
ListIterator it=s.ListIterator();
for(字符串a:args)
s、 添加(a);
if(it.hasNext())
String item=it.next();
系统输出打印项次;
}
}

修改基础列表后,不允许继续在迭代器上迭代。在这里,您在向
s
添加一些项目之前创建迭代器,然后在添加之后继续对其执行
hasNext()
next()
,从而导致for ConcurrentModificationException的
ConcurrentModificationException
:“通常不允许一个线程在另一个线程迭代集合时修改集合”

这只是意味着,如果仍然有一个打开的迭代器,则不允许修改列表,因为迭代器循环将中断。请尝试将
ListIterator It=s.ListIterator();
移动到for循环之后

我不明白为什么我一直得到它,即使我没有看到任何并发的修改正在进行

import java.util.*;

public class SomeClass {
    public static void main(String[] args) {
        List<String> s = new ArrayList<>();
        ListIterator<String> it = s.listIterator();

        for (String a : args)
            s.add(a);

        if (it.hasNext())
            String item = it.next();

        System.out.println(s);
    }
}
在创建迭代器和开始使用迭代器之间,您向要迭代的列表添加了参数。这是一个并发修改

    ListIterator<String> it = s.listIterator();  

    for (String a : args)
        s.add(a);                    // concurrent modification here

    if (it.hasNext())
        String item = it.next();     // exception thrown here
ListIterator it=s.ListIterator();
for(字符串a:args)
s、 在此处添加(a);//并发修改
if(it.hasNext())
String item=it.next();//此处引发异常
在完成向列表中添加元素后创建迭代器:

    for (String a : args)
        s.add(a); 

    ListIterator<String> it = s.listIterator();  
    if (it.hasNext())
        String item = it.next();
for(字符串a:args)
s、 添加(a);
ListIterator it=s.ListIterator();
if(it.hasNext())
String item=it.next();

为了避免出现
ConcurrentModificationException
,您应该这样编写代码:

import java.util.*;

public class SomeClass {

    public static void main(String[] args) {
        List<String> s = new ArrayList<String>();

        for(String a : args)
            s.add(a);

        ListIterator<String> it = s.listIterator();    
        if(it.hasNext()) {  
            String item = it.next();   
        }  

        System.out.println(s);

    }
}
import java.util.*;
公共类{
公共静态void main(字符串[]args){
列表s=新的ArrayList();
for(字符串a:args)
s、 添加(a);
ListIterator it=s.ListIterator();
如果(it.hasNext()){
String item=it.next();
}  
系统输出打印项次;
}
}

java.util.ListIterator
允许您在迭代过程中修改列表,但不能在创建列表和使用列表之间进行修改。

如果上述解决方案无法正常工作。您可以使用旧for循环在添加新项的同时迭代列表。请参见下面的示例:

import java.util.*;

public class SomeClass {
    public static void main(String[] args) {
        ArrayList<AClass> aList = new ArrayList<AClass>(); // we will iterate this


        // this will cause ConcurrentModificationException. 
        // Since we are iterating the list, at the same time modifying it.
        /*for(AClass a: aList){
           aList.add(someMethod(a));
        }*/

        // old fashion for-loop will help
        int limit = aList.size();
        for(int i=0; ctr<limit; ++i){
           AClass a = aList.get(i);
           aList.add(someMethod(a));
        }


    }
}
import java.util.*;
公共类{
公共静态void main(字符串[]args){
ArrayList aList=new ArrayList();//我们将迭代此
//这将导致ConcurrentModificationException。
//因为我们正在迭代列表,同时修改它。
/*对于(a类:列表){
添加(方法(a));
}*/
//旧的循环方式会有所帮助
int limit=aList.size();
对于(int i=0;ctr这不起作用:

LinkedList<String> linkedList = new LinkedList<String>();
ListIterator listIterator = linkedList.listIterator();
linkedList.add("aa");
linkedList.add("bb");
LinkedList LinkedList=新建LinkedList();
ListIterator ListIterator=linkedList.ListIterator();
linkedList.add(“aa”);
linkedList.add(“bb”);
这起到了作用:

LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("aa");
linkedList.add("bb");
ListIterator listIterator = linkedList.listIterator();
LinkedList LinkedList=新建LinkedList();
linkedList.add(“aa”);
linkedList.add(“bb”);
ListIterator ListIterator=linkedList.ListIterator();

要理解这一点,让我们看看HashMap实现的源代码:

public class HashMap<K, V> extends AbstractMap<K, V> implements Cloneable, Serializable{
公共类HashMap扩展了AbstractMap实现了可克隆、可序列化{
其中包含哈希迭代器,如下所示:

private abstract class HashIterator {
    ...
    int expectedModCount = modCount;
    ...

    HashMapEntry<K, V> nextEntry() {
        if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        .... 
        }
私有抽象类哈希迭代器{
...
int expectedModCount=modCount;
...
HashMapEntry nextEntry(){
if(modCount!=预期的modCount)
抛出新的ConcurrentModificationException();
.... 
}
每次创建迭代器时:

  • 将创建一个计数器expectedModCount,并将其设置为modCount值作为入口检查点
  • 在使用put/get(添加/删除)的情况下,modCount会增加
  • nextEntry迭代器的方法正在使用当前modCount检查此值,如果它们不同,则会引发并发修改异常
要避免这种情况,您可以:

import java.util.*;

public class SomeClass {
    public static void main(String[] args) {
        ArrayList<AClass> aList = new ArrayList<AClass>(); // we will iterate this


        // this will cause ConcurrentModificationException. 
        // Since we are iterating the list, at the same time modifying it.
        /*for(AClass a: aList){
           aList.add(someMethod(a));
        }*/

        // old fashion for-loop will help
        int limit = aList.size();
        for(int i=0; ctr<limit; ++i){
           AClass a = aList.get(i);
           aList.add(someMethod(a));
        }


    }
}
  • 将贴图转换为数组(不建议用于大型贴图)
  • 使用并发映射或列表类(/)
  • 锁映射(这种方法消除了多线程的优点)
这将允许您同时迭代和添加或删除元素,而不会引发异常

并发映射/列表迭代器是一个“弱一致”迭代器,它将 永远不要抛出ConcurrentModificationException,并保证 遍历迭代器构造时存在的元素, 并且可能(但不保证)反映任何修改 施工之后

看看oracle页面

当对象的并发修改不允许时,检测到该修改的方法可能会引发此异常

请注意,此异常并不总是表示对象已被其他线程并发修改。如果单个线程发出的方法调用序列违反了对象的约定,则对象可能引发此异常。例如,如果线程在其上迭代时直接修改集合如果集合具有fail fast迭代器,迭代器将引发此异常

在本例中,您在创建迭代器后修改了集合,因此遇到了异常