同时从列表中删除对象

Remove object from list concurrently

我想从列表中删除一个对象,但我有一个线程一直在使用迭代器检查同一个列表。我已经有了要删除的对象,是否必须使用另一个迭代器循环遍历列表,同时检查对象,然后使用迭代器将其删除,或者是否有更简单的方法?现在,如果我尝试使用 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);
    }
}

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

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

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

一个Iterator简单的实现了遍历。如果在迭代列表时从列表中删除元素,即使 hasNext 返回 truenext 方法也会抛出 NoSuchElementException。添加另一个迭代器不会解决问题。您仍然会在删除内容的同时删除它们。

你希望达到的结果是什么?是否要 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);
}

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

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,无需任何同步。