arraylist并发修改
我正在用java创建一个multithreading聊天。 当用户u1向用户u2发送消息但用户u2未连接时,用户u1将消息发送给服务器,用户u2将在连接到服务器后收到消息。 未发送的消息将添加到ArrayList。 一旦用户连接,他就会检查他是否是待处理消息的接收者。 如果是,则将消息发送给他,然后从待处理消息列表中删除。 我是这样做的:
for(Iterator 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)
我如何解决它? 是因为我正在使用迭代器吗?
而不是这个
pendingmsgs.remove(pendingmsg);
使用
itpendingmsgs.remove();
ArrayList
Iterator
快速失败 ,因此当您使用Iterator
ArrayList
,如果基础ArrayList
被Iterator
本身提供的除add
和remove
之外的任何方法修改,它将抛出ConcurrentModificationException
并将挽救。
在当前实现中,当您在某些条件下循环遍历列表时,您还通过调用基础ArrayList
上的remove
来修改列表,而是调用Iterator
remove
方法。
来自Java Docs:
这个类的iterator和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时候对列表进行结构修改,除了通过迭代器自己的remove或add方法之外,迭代器将抛出ConcurrentModificationException。 因此,在并发修改的情况下,迭代器快速而干净地失败,而不是在未来的未确定时间冒任意,非确定性行为的风险。
请注意,迭代器的快速失败行为无法得到保证,因为一般来说,在存在不同步的并发修改时,不可能做出任何硬性保证。 失败快速迭代器会尽最大努力抛出ConcurrentModificationException。 因此,编写依赖于此exception的程序以确保其正确性是错误的:迭代器的快速失败行为应该仅用于检测错误。
除非通过iterator
实例本身,否则不允许在迭代时修改列表。 你必须调用itpendingmsgs.remove()
。
代替
pendingmsgs.remove(pendingmsg);
使用
itpendingmsgs.remove();
看到:
如果在迭代正在进行中以除调用此方法之外的任何方式修改基础集合,则未指定迭代器的行为。
来源: Java API
基于文档ArrayList api 此类的iterator和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时候对list进行结构修改,除非通过迭代器自己的remove或add方法,迭代器将抛出ConcurrentModificationException。
在迭代它时,不应该从集合中删除它。 您应该使用迭代器的remove方法。
for(Iterator itpendingmsgs = pendingmsgs.iterator(); itpendingmsgs.hasNext();) { String pendingmsg = itpendingmsgs.next(); String dest = pendingmsg.substring(4); if (protocol.author.equals(dest)) { sendMsg(msg); itpendingmsgs.remove(); }
}