【问题标题】:arraylist concurrent modification [closed]arraylist 并发修改
【发布时间】:2012-05-28 06:53:33
【问题描述】:

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

我该如何解决?是因为我用的是迭代器吗?

【问题讨论】:

  • 迭代时不能使用remove

标签: java arraylist iterator concurrentmodification


【解决方案1】:

而不是这个

pendingmsgs.remove(pendingmsg);

使用

itpendingmsgs.remove();

Iterator of ArrayListfail fast ,因此当您使用 Iterator 迭代 ArrayList 时,如果底层 ArrayList 被除 @ 以外的任何方法修改987654329@ 和 removeIterator 本身提供,它会抛出 ConcurrentModificationException 并退出。

在您当前的实现中,当您在特定条件下循环遍历列表时,您还可以通过在底层ArrayList 上调用remove 来修改列表,而不是调用Iteratorremove 方法。

来自 Java 文档:

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

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

【讨论】:

    【解决方案2】:

    除了通过iterator 实例本身之外,您不能在迭代列表时修改它。您必须致电itpendingmsgs.remove()

    【讨论】:

      【解决方案3】:

      代替

      pendingmsgs.remove(pendingmsg);
      

      使用

      itpendingmsgs.remove();
      

      见:

      如果底层的迭代器的行为是未指定的 在迭代过程中以任何方式修改集合 除了调用这个方法。

      来源:Java API

      【讨论】:

        【解决方案4】:

        基于文档ArrayList api 此类的迭代器和 listIterator 方法返回的迭代器是快速失败的:如果列表在迭代器创建后的任何时间被结构修改,除了通过迭代器自己的任何方式删除或添加方法,迭代器将抛出 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();
        }
        

        }

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-08-28
          • 2012-12-24
          • 1970-01-01
          • 2011-10-15
          • 1970-01-01
          相关资源
          最近更新 更多