2012-05-21 118 views
0

我正在用java创建一个多线程聊天。当用户u1向用户u2发送消息但用户u2未连接时,用户u1将该消息发送给服务器,并且用户u2在他连接到服务器后将接收该消息。未发送的消息将被添加到ArrayList。一旦用户连接,他会检查他是否是未决消息的收件人。如果他是,则将消息发送给他,然后从待处理消息列表中删除。这就是我要做的事:数组并发修改

for(Iterator<String> itpendingmsgs = pendingmsgs.iterator(); itpendingmsgs.hasNext();) { 
    String pendingmsg = itpendingmsgs.next(); 
    String dest = pendingmsg.substring(4);    
    if (protocol.author.equals(dest)) { 
     sendMsg(msg); 
     pendingmsgs.remove(pendingmsg); 
    } 
} 

这就是我得到:

Exception in thread "Thread-3" java.util.ConcurrentModificationException 
at java.util.AbstractList$Itr.checkForComodification(Unknown Source) 
at java.util.AbstractList$Itr.next(Unknown Source) 
at ChatServer$ClientConnection.run(ChatServer.java:383) 
at java.lang.Thread.run(Unknown Source) 

如何解决呢?是因为我在使用迭代器吗?

+0

不能使用删除,而迭代 – keyser

回答

3

代替此

pendingmsgs.remove(pendingmsg); 

使用

itpendingmsgs.remove(); 

ArrayListIteratorfail fast,因此,尽管要使用的Iterator遍历ArrayList如果底层ArrayList被其他任何方法改性比addremove由提供10本身它会抛出ConcurrentModificationException并且将被保释出来。

在你当前的实现,而你是通过在一定条件下,你也可以通过调用底层ArrayListremove修改清单列表循环,而不是调用Iteratorremove方法。

从Java文档:此类的迭代器返回和的ListIterator

的迭代器 方法是快速失败的:如果列表在任何 时间结构上修改迭代器创建之后,以任何方式除了通过 迭代器自己的remove或add方法,迭代器将抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快并且干净地失败,而不是冒着在将来确定的时间 处的任意的,不确定的行为冒险。

注意,迭代器的快速失败行为不能得到保证 ,因为它是,一般来说,不可能作出任何硬性保证 不同步并发修改的存在。迭代器在尽力而为 的基础上抛出ConcurrentModificationException时出现快速失败 。因此,编写一个依赖于此例外的 的程序是错误的,因为它的正确性: 迭代器的故障快速行为应仅用于检测错误。

1

除了通过iterator实例本身,您不得在遍历整个列表时修改列表。您必须致电itpendingmsgs.remove()

1

而不是

pendingmsgs.remove(pendingmsg); 

使用

itpendingmsgs.remove(); 

参见:

如果底层 集合被修改,迭代过程中的迭代器的行为是不确定的除了通过调用此方法以外的任何方式 。

来源:Java API

1

基于文档ArrayList api此类的iterator和listIterator方法返回的迭代器是快速失败的:如果列表在任何时间从结构上修改创建迭代器之后,在任何除了通过迭代器自己的remove或add方法外,迭代器将抛出ConcurrentModificationException。

当您迭代它时,您不应该从集合中移除它。您应该使用迭代器的remove方法。

for(Iterator<String> itpendingmsgs = pendingmsgs.iterator(); itpendingmsgs.hasNext();) { 
String pendingmsg = itpendingmsgs.next(); 
String dest = pendingmsg.substring(4);    
if (protocol.author.equals(dest)) { 
    sendMsg(msg); 
    itpendingmsgs.remove(); 
} 

}