【问题标题】:Sometimes receiving java.util.ConcurrentModificationException, sometimes not. Can't figure out why有时会收到 java.util.ConcurrentModificationException,有时不会。不知道为什么
【发布时间】:2014-03-04 17:11:23
【问题描述】:

首先这里是错误消息:

线程“Thread-2”中的异常
java.util.ConcurrentModificationException
在 java.util.ArrayList$Itr.checkForComodification(未知来源)
在 java.util.ArrayList$Itr.next(未知来源)
在 zom.mainpac.Game.render(Game.java:218)
在 zom.mainpac.Game.run(Game.java:154)
在 java.lang.Thread.run(Unknown Source)

在第 218 行渲染我的对象数组列表:

    for(Objects e : list){
    e.render(g);
    }

然后是第 154 行的渲染函数:

    render();

...

private void render() {

    BufferStrategy bufferStrategy = this.getBufferStrategy();

    if (bufferStrategy == null) {

        this.createBufferStrategy(2);
        return;

    }

问题可能是因为我的笔记本电脑无法渲染所有对象SOMETIMES,所以它放弃了。所以我只是想知道是否有更好的方法可以做到这一点而不会一直崩溃。

【问题讨论】:

    标签: java crash render


    【解决方案1】:

    您遇到线程安全问题和/或列表访问问题。您可能希望将列表/数组项复制到局部变量中,以便在遍历和/或考虑同步块时无法修改列表。

    您的实例列表变量正在被一个线程访问(执行 for 循环),然后另一个线程出现并且可能想要访问它。要解决而不是使用实例变量执行 for 循环,请创建一个局部变量并从 .list 中复制项目。现在你有了一个其他线程无法访问的私有列表

    【讨论】:

    • 所以你说我的数组列表被访问得太早了?请解释一下我不明白你的意思
    • 你的列表变量,是实例变量吗?
    【解决方案2】:

    出现问题是因为您的代码在迭代时修改了列表。

    • 如果你只有一个线程读取/写入列表,那么最有可能调用

      this.createBufferStrategy(2);

    有时会在同一个数组列表中添加一些元素。如果您将使用列表的副本进行迭代,则可以修复异常:

    for (Objects e : new ArrayList(list)) {
       e.render(g);
    }
    
    • 如果您有多个线程来读取/写入列表,请改用 java.util.concurrent.CopyOnWriteArrayList

    【讨论】:

      【解决方案3】:

      For each 使用迭代器进行循环,因此如果您碰巧从该列表中删除某些内容,则在迭代期间很容易受到此类异常的影响。例如,如果您在渲染时从您的游戏列表中删除一个图块或精灵,就会发生这种情况。如果您不经常修改列表,如果您希望在迭代时修改列表(让您不必创建列表的副本),则可以使用 CopyOnWriteArrayList,但重要的是要注意您应该首先了解导致的行为这个,不要盲目修复。

      【讨论】:

      • 没问题,确保您知道使用该 List 类型所涉及的牺牲,并且您发现了可能存在的错误。