【问题标题】:Iterator, ListIterator and List迭代器、列表迭代器和列表
【发布时间】:2012-10-11 02:51:08
【问题描述】:

我遇到了一个我无法弄清楚的问题。 如果你们能帮助我,那就太好了=)

我有一个 Lobby.Class,它有一个 draw() 方法:

public void draw() {
    //USE ITERATOR TO DRAW
    Iterator<Player> itr = players.iterator();
    while(itr.hasNext()) {
        Player player = itr.next();
        int off = players.indexOf(player); //THE CORRECT HEIGHT
        player.draw(off);
    }
}  

请注意,这是一个服务器/客户端游戏

Lobby.Class 还有一个名为 addPlayer() 的方法

public void addPlayer(String _playerName, String _class, String _string_id) {

    int _id = Integer.parseInt(_string_id);

    //CREATE THE NEW PLAYER
    Player new_player = new Player(x, y, _id, _playerName, _class);

    //IF THIS PLAYER IS ME
    if(new_player.getID() == id) {

        me = new_player;

    } else {

        //TELL THE NEW PLAYER I EXIST
        ClientValue.getClient().iExist(_id);

                    //THIS WILL SEND TO CLIENT THAT WILL SEND TO THE SERVER
                    //THAT WILL LOOK FOR THE ID AND SEND TO CLIENT OF THAT ID
                    //AND THE CLIENT WILL SEND TO LOBBY UPDATE PLAYERS()
    }

    players.add(new_player);

    chat.appendChat(chat.joinString(_playerName, _class));
}

Lobby.Class 还有一个名为 updatePlayers() 的方法

public void updatePlayers(String _playerName, String _class, String _string_id) {

    //THIS IS CALLED WHEN THE SERVER TELLS THIS PLAYER
    //ABOUT OTHER PLAYERS

    int _id = Integer.parseInt(_string_id);

    //CREATE THE NEW PLAYER
    Player new_player = new Player(x, y, _id, _playerName, _class);
    players.add(new_player);

}

现在我的问题是玩家列表,当我进入大厅时addPlayer()会在2个玩家加入时同时运行,或者当updatePlayers()addPlayer()一起运行时

我得到的异常是:ConcurrentModificationException

我缺少两种方法,1 用于添加玩家,如果可能的话,使用迭代器,1 用于删除玩家。这样我就不会在通过它或添加/删除它时收到修改玩家列表的错误。

我尝试过使用 Iteror 和 ListIterator,但由于我以前从未使用过它们,我不知道该怎么做。我需要一些关于如何做到这一点的建议。 非常感谢提前=)

解决方案:

private List<Player> players = Collections.synchronizedList(new ArrayList<Player>());

    public synchronized void playersList(String cmd, Player _player) {

    Iterator<Player> itr = players.iterator();

    if(cmd.equals("draw")) {

        while(itr.hasNext()) {

            Player player = itr.next();
            int off = players.indexOf(player);
            player.draw(off);
        }

    } else if(cmd.equals("add")) {

        players.add(_player);

    } else if(cmd.equals("remove")) {

        players.remove(_player);
    }
}

【问题讨论】:

  • "这个类的 iterator 和 listIterator 方法返回的迭代器是快速失败的:如果列表在迭代器创建后的任何时间被结构修改,除了通过迭代器自己的方式删除或添加方法,迭代器将抛出 ConcurrentModificationException。"。你无法避免它,see
  • 好的,但是如果我在类的顶部初始化一个迭代器,然后使用该迭代器来添加和删除,那会起作用吗?另外我注意到Iterator没有add方法,这是否意味着我必须使用ListIterator?
  • 你看到了你的链接,我看看能不能找到解决办法。
  • 为了避免ConcurrentModificationException被抛出,使用迭代器自己的方法。如果你使用Listremove() 方法,异常会一直抛出,对我来说,我总是使用ListIterator
  • 非常感谢您清理东西 =) 会尝试并回发

标签: java list iterator listiterator


【解决方案1】:

你需要同步访问列表,一次只允许一个线程访问列表。

您可以在每个访问点周围使用synchronized 块(包括整个绘制方法),或者您可以使用Collections#synchronizedList 将播放器列表包装在线程安全列表中,或者您可以使用@ 来代替迭代器987654324@玩家方法

Player[] arrayOfPlayers = players.toArray(new Player[players.size()]);

你仍然要去synchronized这个调用,但你只锁定了一行,而不是整个循环

【讨论】:

  • 好的,非常感谢。但是与 Lobby.Class 对话的唯一线程是 Client.Class。所以只有一个线程,我还需要同步还是使用线程安全列表?很抱歉所有问题。
  • 嗯,实际上,看起来有两个线程正在访问您的列表,否则您不会有并发修改异常。迭代时不能更改列表。您需要同步访问权限,以便更新或迭代它,而不是同时进行
  • 在这种情况下为什么不使用 CopyOnWriteArrayList?
  • @Mik378 好主意(我今天学到了一些东西),但它确实增加了很多开销,synchroniedList 会更快吗??
  • @MadProgrammer 如果您的写作线程少而阅读线程多,那么 CopyOnWriteArraylist 将是完美的。相反,如果写入的事实非常频繁,由于潜在的大量 arraycopy 使用,性能会下降。因此可以有效地使用 synchronizedList 代替。无论如何,没有测试什么都做不了:)
猜你喜欢
  • 1970-01-01
  • 2019-07-05
  • 1970-01-01
  • 1970-01-01
  • 2011-07-19
  • 1970-01-01
  • 2018-04-26
  • 2012-01-14
  • 2013-02-07
相关资源
最近更新 更多