没有额外的线程运行时获取ConcurrentModificationException

时间:2014-03-25 13:30:52

标签: java multithreading

如果我在方法中声明Iterator,则以下方法有效。如果我在方法之外声明它,它会导致ConcurrentModificationException。我没有任何其他线程运行任何并发操作。我不明白为什么在方法内外声明它之间的区别。我可以在每种方法中声明迭代器,但觉得效率不高。请指出什么是错的。谢谢。

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Scanner;

public class Linker {

    private static LinkedList<String> list = new LinkedList();

    public static void main(String[] args){
        load("sample.txt");
        find("Sam");
    }

    public static void load(String sourceName){
        try {
            Scanner in = new Scanner(new File(sourceName));
            while (in.hasNextLine()){
                String name = in.nextLine();
                list.add(new String(name));
            }
            in.close();
        }catch (FileNotFoundException e){
            System.out.println("File not found.");
        }
    }

    //static ListIterator<String> iterator = list.listIterator(); //causes ConcurrentModificationException
    public static int find(String name){
        ListIterator<String> iterator = list.listIterator();//this works
        while (iterator.hasNext()){
            String x = iterator.next();
        }
        return -1;
    }
}

4 个答案:

答案 0 :(得分:2)

在对此方法的两次调用之间修改theDirect列表时,可能会出现此问题。

当在方法中获得迭代器时,每次调用方法时都将使用“新鲜”迭代器。

当在方法之外获得迭代器时,(在第二次调用期间,在其他人修改了列表之后),它只会注意到“嘿,其他人用这个列表做了些什么,我不能确定我不再处于一致的状态“,并用ConcurrentModificationException拯救。

答案 1 :(得分:1)

Java中的列表可用于修改计数。也就是说,在让任何人使用ListIterator之前,请在创建时存储modcount。然后在迭代检查时查看创建时的modcount是否大于当前的modcount。

您正在做的是在列表填充之前创建ListIterator,将List的当前modcount设置为0。

private List<String> list = new ArrayList<>();
private ListIterator<String> itr = list.listIterator(); //at this point mod count is 0

public static void load(String sourceName){
        list.add("Foo");// increment mod count by 1
}

因此,加载后的任何修改都会将modcount增加1.并且由于modcount在创建ListIterator之前为0,因此任何迭代器调用都将引发一个编码。

另一种解决方案是在加载方法完成添加后创建ListIterator。此时,modcount不会改变。

答案 2 :(得分:0)

应尽快使用迭代器。因此,在方法中创建它是绝对有意义的。

然而,将其创建为实例字段确实没有意义。我假设您在其他方法中添加和删除值。每次执行时,都会修改列表,因此下一次访问迭代器将抛出ConcurrentModificationException

答案 3 :(得分:0)

如@ Marco13所示,问题是在调用方法之间修改了theDirect。大多数馆藏的文档与ArrayList上的文档类似:​​

  

此类的迭代器和listIterator返回的迭代器   方法是快速失败的:如果列表在结构上被修改了   创建迭代器之后的时间,除了通过之外的任何方式   迭代器自己删除或添加方法,迭代器会抛出一个   ConcurrentModificationException的。因此,面对并发   修改,迭代器快速而干净地失败,而不是   在不确定的时间冒着任意的,非确定性的行为   在将来。

这意味着一旦创建了迭代器,就不能改变列表本身(除了通过迭代器的方法)。