arraylist并发修改

时间:2012-05-21 18:52:37

标签: java arraylist iterator concurrentmodification

我在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)

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

4 个答案:

答案 0 :(得分:3)

而不是这个

pendingmsgs.remove(pendingmsg);

使用

itpendingmsgs.remove();
Iterator的{​​{1}} fail fast ,所以当您使用ArrayList ArrayList进行迭代时{1}}由Iterator本身提供的ArrayListadd以外的任何方法进行修改,它会抛出remove并将纾困。

在当前实现中,当您在特定条件下循环浏览列表时,您还要通过调用基础Iterator上的ConcurrentModificationException来修改列表,而不是调用remove方法{ {1}}。

来自Java Docs:

  

此类的迭代器和listIterator返回的迭代器   方法是快速失败的:如果列表在结构上被修改了   创建迭代器之后的时间,除了通过之外的任何方式   迭代器自己删除或添加方法,迭代器会抛出一个   ConcurrentModificationException的。因此,面对并发   修改,迭代器快速而干净地失败,而不是   在不确定的时间冒着任意的,非确定性的行为   在将来。

     

请注意,无法保证迭代器的快速失败行为   一般来说,不可能做出任何硬性保证   存在不同步的并发修改。快速失败   迭代器抛出ConcurrentModificationException就是尽力而为   基础。因此,编写一个依赖的程序是错误的   关于它的正确性的这个例外:快速失败的行为   迭代器应该只用于检测错误。

答案 1 :(得分:1)

除非通过iterator实例本身,否则不允许在迭代时修改列表。您必须致电itpendingmsgs.remove()

答案 2 :(得分:1)

而不是

pendingmsgs.remove(pendingmsg);

使用

itpendingmsgs.remove();

请参阅:

  

如果是底层的,则未指定迭代器的行为   在迭代以任何方式进行时,都会修改集合   除了通过调用此方法。

来源:Java API

答案 3 :(得分:1)

基于文档ArrayList api 此类的迭代器和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时候对列表进行结构修改,除了通过迭代器自己的删除或添加方法,迭代器将抛出一个ConcurrentModificationException。

在迭代时,不应该从集合中删除它。你应该使用iterator的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();
}

}