ConcurrentModificationException,但没有修改

时间:2014-10-01 02:47:51

标签: java concurrentmodification

我目前正在使用Java编写多人游戏。我当前的代码(即获得错误)就是这样。

@Override
public void onClose(WebSocket conn, int code, String reason, boolean remote){
    System.out.println("Socket disconnected.");

    for(Game g : Lobby.games){
        if(g.hasPlayer(new Player(conn))){
            Player ourPlayer = null;

            for(Player p : g.getPlayers()){
                if(p.getSocket() == conn){
                    ourPlayer = p;
                    break;
                }
            }

            if(ourPlayer == null) return;

            g.removePlayer(ourPlayer);

            for(Player p : g.getPlayers()){
                send(p.getSocket(), Messages.SEND_REMOVE_PLAYER + ourPlayer.getName());
            }

            if(g.getPlayers().size() == 0){
                Lobby.removeGame(g);
            }
        }
    }
}

现在请不要询问onClose等功能。这不会导致问题。

我收到以下行的ConcurrentModificationException:

for(Game g : Lobby.games){

Lobby.games是" Game"的空数组列表。在Lobby.java里面。通过其他功能添加游戏。

public static ArrayList<Game> games = new ArrayList<Game>();

更新:这是removeGame:

public static void removeGame(Game game){
    Iterator<Game> itr = games.iterator();

    while(itr.hasNext()){
        Game g = itr.next();

        if(g.getId() == game.getId()){
            System.out.println("Game "+g.getId()+" removed");
            itr.remove();
        }
    }
}

抱歉模糊不清。如果您需要更多代码,我一定会添加它。谢谢!

2 个答案:

答案 0 :(得分:2)

你的问题(几乎可以肯定)在这里:

for(Game g : Lobby.games) {
    // other code
    if (g.getPlayers().size() == 0){
        Lobby.removeGame(g);
    }
}

如果Lobby.removeGame(g)更改Lobby.games的内容,那么您将在迭代时修改Lobby.gamesforeach循环隐式迭代Lobby.games

使用迭代器并调用Iterator.remove(),或者在循环后保存要删除的游戏集合,或者重新组织代码以避免这种情况。

答案 1 :(得分:0)

您的Lobby.removeGame(g)调用意味着您打算修改列表,尽管您现在正在迭代它,这将完全使隐式排序无效。

如果您需要这样做,请使用明确的反向循环,以便您只修改列表中不会影响您尚未获得的部分顺序的部分:

for(int i=Lobby.games.size()-1; i>-1; i--) {
  Game g = Lobby.games.get(i);

  // this is now safe, because you're only ever going to see
  // indices lower than the current "i", and the removal
  // only how long Lobby.games is *after* "i", not before it.
  Lobby.games.remove(g)
}