Java 同时从列表中删除对象

Java 同时从列表中删除对象,java,multithreading,java.util.concurrent,Java,Multithreading,Java.util.concurrent,我想从列表中删除一个对象,但是我有一个线程,它使用迭代器一致地检查同一个列表。我已经有了要删除的对象,我是否必须使用另一个迭代器在列表中循环,同时检查对象,然后使用迭代器删除它有没有更简单的方法?现在,如果我尝试使用remove方法从列表中删除对象,线程上的迭代器会给我一个NoSuchElementException //Threaded loop. Iterator<Client> playersIterator = getPlayers().iterator(); while(p

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