同时从列表中删除对象

时间:2015-10-12 15:34:35

标签: java multithreading java.util.concurrent

我想从列表中删除一个对象,但是我有一个使用迭代器一致地检查相同列表的线程。我已经有了要删除的对象,我是否必须使用另一个迭代器来遍历列表,同时检查对象,然后使用迭代器删除它,或者有更简单的方法吗?现在,如果我尝试使用remove方法从列表中删除对象,则线程上的迭代器会给我一个NoSuchElementException

//Threaded loop.
Iterator<Client> playersIterator = getPlayers().iterator();
while(playersIterator.hasNext()){
    Client c = playersIterator.next(); //NoSuchElementException
    if(c.getSocket().isClosed()) {
        playersIterator.remove();
        if(getHost() == c) {
            assignNewHost();
        }
        getServer().getLobbyHandler().updateGames();
    }
}


//Use an iterator to remove?
public void removePlayerFromGame(Client client) {
    Game g = getServer().getGame(client);
    if(g != null) {
       g.getPlayers().remove(client);
    }
}

3 个答案:

答案 0 :(得分:0)

使用synchronized来控制对资源的访问权限......

https://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html

synchronized {
     // your code will wait before removing the object
     g.getPlayers().remove(client);
}

答案 1 :(得分:0)

Iterator只是实现遍历。如果您在迭代时从列表中删除元素,即使next返回NoSuchElementExceptionhasNext方法也会抛出true。添加另一个迭代器不会解决问题。你仍然会在通过它们的同时删除它们。

您希望实现的结果是什么?你想让removePlayerFromGame等到循环执行完毕吗?在这种情况下,您需要同步访问权限:

Collection<Client> players = getPlayers();
synchronized(players) {
    Iterator<Client> playersIterator = getPlayers().iterator();
    // Iterator is safe from deletion
}

Collection<Client> players = getPlayers();
synchronized(players) {
    // Delete when it is safe to do so
    g.getPlayers().remove(client);
}

答案 2 :(得分:0)

不是删除对象,而是简单地将其标记为删除,并实际删除并行线程

while(playersIterator.hasNext()){
    Client c = playersIterator.next(); //NoSuchElementException
    if (c.isMarked) {
        playersIterator.remove();
    } else if(c.getSocket().isClosed()) {
        ...

其中isMarked

volatile boolean isMarked=false;

并标记要删除的对象,可以将isMarked设置为true,而无需任何同步。