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