向LinkedList添加元素时出现并发修改错误

时间:2012-04-13 02:51:59

标签: java

我有一个LinkedList对象列表。

    List<LinkedList<File1>> backup = new ArrayList<LinkedList<File1>>();

LinkedList包含一些元素。我需要通过单击按钮动态添加其他元素。在这样做时,我遇到了并发修改错误。我真的不明白为什么会出现这个错误。这是代码:

private void jButton5ActionPerformed(java.awt.event.ActionEvent evt)      
{                                         
    // When JOIN button is clicked
    int parent_node,dist_node;
    // List<File1> temp_list = new ArrayList<File1>();
    File1 f_new = new File1();
    parent_node = Integer.parseInt(jTextField4.getText());
    dist_node = Integer.parseInt(jTextField5.getText());
    LinkedList<File1> tmp_bk = backup.get(parent_node);
    System.out.println("parent node : " + parent_node);
    System.out.println("dist node : " + dist_node);
    System.out.println("no of lists : " + backup.size());
    f_new.nod = backup.size();
    f_new.dist = dist_node;
    // temp_list.add(f_new);
    tmp_bk.add(f_new);

    ListIterator itr = it_bk.get(parent_node);
    while(itr.hasNext())
    {
        File1 f = (File1)itr.next();
        System.out.println("NODE : " + f.nod + "DIST : " + f.dist);
    }

}     

3 个答案:

答案 0 :(得分:6)

这可能是因为您正在编辑列表,然后尝试使用原始迭代器。集合API doesn't allow that。编辑列表后需要创建新的迭代器。

  

例如,一个线程通常不允许修改Collection而另一个线程正在迭代它。通常,在这些情况下,迭代的结果是不确定的。如果检测到此行为,某些Iterator实现(包括JRE提供的所有通用集合实现的实现)可能会选择抛出此异常。执行此操作的迭代器称为失败快速迭代器,因为它们快速而干净地失败,而不是在未来的未确定时间冒着任意的,非确定性行为的风险。

     

请注意,此异常并不总是表示某个对象已被另一个线程同时修改。如果单个线程发出违反对象合同的一系列方法调用,则该对象可能会抛出此异常。例如,如果线程在使用失败快速迭代器迭代集合时直接修改集合,则迭代器将抛出此异常。

答案 1 :(得分:1)

首先,如果你真的希望人们把注意力集中在你的问题上,那么你应该以标准的英语清楚地询问它们。

其次,您应该准确地指出您的代码中的ConcurrentModificationError。

最后,什么是 it_bk ?它只是在您的代码中显示而没有任何解释。如果它是ListIterators的ArrayList,那么它的parent_node-th元素当然可能处于不确定hasNext()或next()是否安全的状态。我猜你用 tmp_bk.add(f_new); 修改了底层集合,因此预先存在的迭代器担心它的不变量可能会被违反。

一般建议:不要创建和保留迭代器(或它们的集合)。当你需要Iterator时,创建它,使用它并放弃它。

答案 2 :(得分:0)

JDK 1.5中的java.lang.Colletions未同步。在早期版本(jdk 1.4)中,你不会发现这个问题。

有多种解决方案可用于解决这些问题,您需要根据用例明智地选择其中一种解决方案。

  • 解决方案1:可以使用list.toArray()将列表转换为数组,并对数组进行迭代。如果列表很大,则不建议使用此方法。

  • 答案2:通过将代码包装在同步块中,可以在迭代时锁定整个列表。如果应用程序具有高度并发性,则此方法会对应用程序的可伸缩性产生负面影响。

  • 答案3:JDK 1.5为您提供了ConcurrentHashMap和CopyOnWriteArrayList类,它们提供了更好的可伸缩性,并且ConcurrentHashMap.iterator()返回的迭代器在保留线程安全性的同时不会抛出ConcurrentModificationException。

  • 答案4:通过Iterator“it”删除当前对象,它具有对底层集合“myStr”的引用。 Iterator对象为此提供了it.remove()方法。