我想从列表中删除一个对象,但是我有一个使用迭代器一致地检查相同列表的线程。我已经有了要删除的对象,我是否必须使用另一个迭代器来遍历列表,同时检查对象,然后使用迭代器删除它,或者有更简单的方法吗?现在,如果我尝试使用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);
}
}
答案 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
返回NoSuchElementException
,hasNext
方法也会抛出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
,而无需任何同步。