【问题标题】:Java ConcurrentModificationException when removing two indexes, current and random one删除两个索引时的 Java ConcurrentModificationException,当前索引和随机索引
【发布时间】:2014-10-26 22:45:00
【问题描述】:

我有一份球员名单。 此列表包含没有目标的玩家。目标意味着一个玩家被另一个玩家瞄准,他们两个是目标,不应该在列表中。

以下循环的目的是遍历所有玩家,并搜索一个目标,如果玩家还没有准备好,它就会调用tick()方法,它基本上会计时目标搜索计时器。 isReady方法基本就是timer == 0

    for (Client c : participants) {
        PlayerTargetDomain dom = c.getTarget();
        if (dom.isReady()) {
            if (dom.getSearchDelay() == 0) {
                SharedTargetDomain d;
                if ((d = search(c)) != null) {
                    participants.removeAll(Arrays.asList(d.getFirst(), d.getSecond()));
                    continue;
                }
            }
            else {
                dom.tickSearchDelay();
            }
        }
        else dom.tick();
    }

现在的 search() 方法,基本上是寻找一个匹配的目标,如果找到它会构建包含当前索引的SharedTargetDomain,以及找到的目标索引对象。

如果从search(Client) 返回的SharedTargetDomain 实例不为空,我将使用removeAll()participants 列表中删除这两个对象

不幸的是,如果我删除其中任何一个,我将收到以下错误:

java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at mod.game.TargetManager.execute(TargetManager.java:24)

第 24 行是这样的:

for (Client c : participants) {

为什么我会得到这个?我已经尝试将 Iterator 用于当前索引,但我仍然收到错误,因为我也在删除另一个索引,但是如果我删除它,另一个与当前索引有什么关系?我真的误会了什么。

谢谢!

Iterator 实现:

    Iterator<Client> itr = participants.iterator();
    while(itr.hasNext()) {
        Client c = itr.next();
        if (c != null) {
            PlayerTargetDomain dom = c.getTarget();
            if (dom.isReady()) {
                if (dom.getSearchDelay() == 0) {
                    SharedTargetDomain d;
                    if ((d = search(c)) != null) {
                        participants.remove(d.getSecond());
                        itr.remove();
                        continue;
                    }
                }
                else {
                    dom.tickSearchDelay();
                }
            }
            else dom.tick();
        }
    }

【问题讨论】:

  • 您使用Iterator 尝试过的代码在哪里? Iterator 在迭代时可以很好地删除元素。
  • 不是当前索引有问题,当您修改其他正在使用的列表时会发生 ConcurrentModificationExceptions。你能告诉我们你使用迭代器的实现吗?
  • @JonTaylor 添加了 Iterator 实现,错误显示在 itr.remove() 行。
  • 问题是participants.remove(d.getSecond());你不能这样使用Iterator。只有it.remove() 是有效调用。
  • 当存在用于迭代集合的迭代器时,您不能修改集合。一个集合修改会导致这个迭代器被破坏,所以这就是你得到这个异常的原因。使用上述形式的 for 循环编译器会为您创建一个迭代器。要解决这个问题,您应该为自己创建迭代器并使用它来删除项目。

标签: java arrays loops exception


【解决方案1】:

你可以使用

CopyOnWriteArrayList 避免此异常

【讨论】:

    【解决方案2】:

    问题是您在迭代时修改集合。

    至少有两种解决方案

    1. 使用索引访问。你会得到很多有趣的处理索引,因为元素会在移除后移动。
    2. 收集您需要删除的元素并在完成迭代后应用所有更改,始终牢记您处理的元素可能已被安排删除,您会获得很多乐趣。

    【讨论】:

    • 选择第二个选项。
    • 你也可以使用 CopyOnWriteArrayList
    • 使用第二个选项,在 for 循环之后都删除了。
    • @YSBhai 所以基本上 CopyOnWriteArrayList 而不是 ArrayList 会解决这个问题吗?
    猜你喜欢
    • 2016-03-29
    • 1970-01-01
    • 2020-08-12
    • 2021-05-11
    • 1970-01-01
    • 2012-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多