【问题标题】:Java "ConcurrentModificationException" runtime error when iterating .next() [duplicate]迭代.next()时出现Java“ConcurrentModificationException”运行时错误[重复]
【发布时间】:2011-07-05 23:46:24
【问题描述】:

根据运行时错误信息,异常发生在下面一行;

VirusData v = iteratorVirusDB.next();

VirusData 是一个具有构造函数和重载构造函数的类,其中包含有关数据库中每个病毒的特定信息,例如;

  • 字符串 vName
  • 字符串定义

重载

  • 带有标记化定义的数组(以 xLength 组分隔)
  • 带有 LCS 令牌的数组
  • 带坡度的浮点数

<VirusData> 类型的iteratorVirusDBVirusDB 的.iterator(),如下所示:

Iterator<VirusData> iteratorVirusDB = virusDB.iterator();

VirusDB&lt;VirusData&gt; 类型的 ArrayList,我在其中存储病毒对象 (此时为名称和定义),以便我以后可以使用它们。

ArrayList <VirusData> virusDB = new ArrayList<VirusData>();

最后,错误发生在使用上述所有解释的方法中:

private void selectDabataseMouseClicked(java.awt.event.MouseEvent evt) {
    while(iteratorVirusDB.hasNext()) {
        VirusData v = iteratorVirusDB.next();               //ERROR LINE
        String vSig = v.signature;                              
        v.tokens = tokenize.raw(vSig, true, tLength);
        ...
     }
     ...
}

我真的可以就如何解决这个问题提供一些帮助和建议,以使程序成功运行。贝娄,完整的 StackTrace:

run:
Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
        at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
        at java.util.AbstractList$Itr.next(AbstractList.java:343)
        at project_clean.Main.selectDabataseMouseClicked(Main.java:275)
        at project_clean.Main.access$100(Main.java:11)
        at project_clean.Main$2.mouseClicked(Main.java:76)
        at java.awt.AWTEventMulticaster.mouseClicked(AWTEventMulticaster.java:253)
        at java.awt.Component.processMouseEvent(Component.java:6270)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3267)
        at java.awt.Component.processEvent(Component.java:6032)
        at java.awt.Container.processEvent(Container.java:2041)
        at java.awt.Component.dispatchEventImpl(Component.java:4630)
        at java.awt.Container.dispatchEventImpl(Container.java:2099)
        at java.awt.Component.dispatchEvent(Component.java:4460)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4577)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4247)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4168)
        at java.awt.Container.dispatchEventImpl(Container.java:2085)
        at java.awt.Window.dispatchEventImpl(Window.java:2478)
        at java.awt.Component.dispatchEvent(Component.java:4460)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

【问题讨论】:

  • 结构上修改ArrayList时迭代器失效。将迭代器保存为成员之间的类状态是可疑的。你为什么这样做?
  • 我刚刚回答了一个关于 ConcurrentModificationException 的问题...stackoverflow.com/questions/5145135/…
  • 好吧,我真的不知道迭代器是如何工作的,我最近才发现它们存在,所以我只是通过反复试验来学习。所以如果我理解正确,我不应该这样做Iterator&lt;VirusData&gt; iteratorVirusDB = virusDB.iterator();?但是我怎么能迭代这样的东西; VirusData v = virusDB.iterator().next(); ?感谢您的建议
  • 啊,请在 StackTrace 中使用复制+粘贴,而不是屏幕截图。
  • @Paŭlo:改了,谢谢建议

标签: java exception iterator arraylist runtime-error


【解决方案1】:

显而易见的解释是您在两次调用之间修改了virusDB。使用迭代器进行迭代时,不得修改向量(通过Iterator / ListIterator 方法除外)。

这段代码会总是抛出ConcurrentModificationException

import java.util.*;

class VirusData {
}

public class Test {

    public static void main(String[] args) {

        List<VirusData> list = new ArrayList<VirusData>() {{
            add(new VirusData());
            add(new VirusData());
            add(new VirusData());
        }};

        Iterator<VirusData> iterator = list.iterator();

        iterator.next();

        list.remove(0);
        VirusData s = iterator.next();
    }
}

来自ConcurrentModificationException的文档:

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

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

如果你的意图是每次调用方法时都遍历整个数据库,我建议你这样做

private void selectDabataseMouseClicked(java.awt.event.MouseEvent evt) {
    Iterator<VirusData> iteratorVirusDB = virusDB.iterator();
    while(iteratorVirusDB.hasNext()) {
        VirusData v = iteratorVirusDB.next();
        String vSig = v.signature;                              

【讨论】:

  • 但是如果一个程序在这种情况下不断地修改一个列表,如何遍历它呢?
  • 您可以使用索引i,将hasNext 替换为i &lt; yourList.size(),将next() 替换为yourList.get(i)
  • 非常感谢 aioobe,您在回答中提出的建议奏效了。但是现在我很困惑,当我这样做时 v.tokens = tokenize.raw(vSig, true, tLength); (在您的建议中省略) 通过修改序列中的元素并没有违反规则。或者术语modification 仅适用于集合“大小”,以便单词仅在添加/删除项目时违反?
  • 列表不关心内容对象本身是否发生变化,它只关心结构修改时,例如添加和删​​除元素,并可能用另一个元素替换一个元素(set(...),也只有这些是列表的修改。当然,如果你的程序是多线程的,你通常不应该修改你的在另一个线程中使用对象时,请使用适当的同步。
  • 如果你有两个线程在同一个列表上工作并且你正在见证ConcurrentModificationException,那么这意味着你的操作是不是线程安全的并且切换迭代样式以避免该异常可能只会导致其他预期较少的异常。例如,一旦通过了i &lt; yourList.size() 对最后一个元素的检查,那么另一个线程可以在访问它之前删除任何元素,并且您会导致IndexOutOfBoundsException,这可能没有什么意义。要解决此问题,请在迭代时复制数组,或添加同步。
【解决方案2】:

当您在修改它的同时迭代它时,会发生并发修改异常。因此,如果您正在修改列表并且在您对其进行迭代时会发生这种情况,请检查您的代码。

【讨论】:

    猜你喜欢
    • 2013-07-15
    • 1970-01-01
    • 1970-01-01
    • 2014-05-23
    • 2013-03-27
    • 2015-07-06
    • 2017-02-24
    • 1970-01-01
    • 2016-11-27
    相关资源
    最近更新 更多