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)

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

4

4 回答 4

3

而不是这个

pendingmsgs.remove(pendingmsg);

采用

itpendingmsgs.remove();

Iteratorof快速失败ArrayList,因此当您迭代使用if 底层被任何方法修改时,它会抛出并退出。ArrayListIteratorArrayListaddremoveIteratorConcurrentModificationException

在您当前的实现中,当您在特定条件下循环遍历列表时,您还通过调用remove底层而ArrayList不是调用remove.Iterator

来自 Java 文档:

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

请注意,不能保证迭代器的快速失败行为,因为一般来说,在存在不同步的并发修改的情况下,不可能做出任何硬保证。快速失败的迭代器会尽最大努力抛出 ConcurrentModificationException。因此,编写一个依赖于这个异常的正确性的程序是错误的:迭代器的快速失败行为应该只用于检测错误。

于 2012-05-21T18:54:00.077 回答
1

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

于 2012-05-21T18:54:15.990 回答
1

代替

pendingmsgs.remove(pendingmsg);

采用

itpendingmsgs.remove();

看:

如果在迭代过程中以除调用此方法之外的任何方式修改了基础集合,则迭代器的行为是未指定的。

来源:Java API

于 2012-05-21T18:55:55.660 回答
1

基于文档ArrayList api 此类的迭代器和 listIterator 方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时间对 list 进行结构修改,除了通过迭代器自己的 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();
}

}

于 2012-05-21T19:02:24.360 回答