Java 同时从列表中删除对象
我想从列表中删除一个对象,但是我有一个线程,它使用迭代器一致地检查同一个列表。我已经有了要删除的对象,我是否必须使用另一个迭代器在列表中循环,同时检查对象,然后使用迭代器删除它有没有更简单的方法?现在,如果我尝试使用remove方法从列表中删除对象,线程上的迭代器会给我一个Java 同时从列表中删除对象,java,multithreading,java.util.concurrent,Java,Multithreading,Java.util.concurrent,我想从列表中删除一个对象,但是我有一个线程,它使用迭代器一致地检查同一个列表。我已经有了要删除的对象,我是否必须使用另一个迭代器在列表中循环,同时检查对象,然后使用迭代器删除它有没有更简单的方法?现在,如果我尝试使用remove方法从列表中删除对象,线程上的迭代器会给我一个NoSuchElementException //Threaded loop. Iterator<Client> playersIterator = getPlayers().iterator(); while(p
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);
}
}
//线程循环。
迭代器playersIterator=getPlayers().Iterator();
while(playersIterator.hasNext()){
客户端c=playersIterator.next();//NoTouchElementException
if(c.getSocket().isClosed()){
playersIterator.remove();
if(getHost()==c){
assignNewHost();
}
getServer().getLobbyHandler().updateGames();
}
}
//使用迭代器删除?
public void removePlayerFromGame(客户端){
Game g=getServer().getGame(客户端);
如果(g!=null){
g、 getPlayers().remove(客户端);
}
}
使用同步
控制对资源的访问
迭代器
只是实现遍历。如果在迭代列表时从列表中删除元素,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);
}
Collection players=getPlayers();
同步(玩家){
迭代器playersIterator=getPlayers().Iterator();
//迭代器不会被删除
}
集合玩家=getPlayers();
同步(玩家){
//在安全的情况下删除
g、 getPlayers().remove(客户端);
}
不需要删除对象,只需将其标记为删除,然后在并行线程中实际删除即可
while(playersIterator.hasNext()){
Client c = playersIterator.next(); //NoSuchElementException
if (c.isMarked) {
playersIterator.remove();
} else if(c.getSocket().isClosed()) {
...
其中,标记为
volatile boolean isMarked=false;
要标记要删除的对象,只需将isMarked
设置为true
,而无需任何同步。我认为最好使用synchronized
块,以便控制对集合的访问,从本质上说,removePlayerFromGame
将在删除之前等待迭代器完成,否则,迭代器将在删除之前等待删除完成。按现状,您无法控制在哪个监视器上同步时发生的情况。它将抛出ConcurrentModificationException
,而不是NoTouchElementException
@AndyTurner,如果您删除一个项并重新初始化迭代器,则中断循环。@DV88如果不是您删除该项,也就是说,只有当集合实现modCount
时,它才是其他线程?@AndyTurner。未提及正在使用的集合类型。问题中唯一可用的信息是next
抛出NoSuchElementException
,而hasNext
返回true
;通常,如果您正在迭代此列表,如@sh0rug0ru所述,请使用synchronized控制对它的访问。例如,调用保存列表以供访问的类。Obv如果您采取该步骤,您将希望确保同步代码尽可能高效。。。。我一直都有这种模式,我从各种外部类添加到队列中,然后在线程中循环并从该队列中删除以处理请求。threaded类是队列的所有者。谢谢,但我正在使用的应用程序不需要响应速度,我多次访问ArrayList。为每个方法使用布尔值将是混乱的。同步这些方法非常有效。
volatile boolean isMarked=false;