我在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 :(得分:3)
而不是这个
pendingmsgs.remove(pendingmsg);
使用
itpendingmsgs.remove();
Iterator
的{{1}} fail fast ,所以当您使用ArrayList
ArrayList
进行迭代时{1}}由Iterator
本身提供的ArrayList
和add
以外的任何方法进行修改,它会抛出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();
}
}