[英]java.util.ConcurrentModificationException on ArrayList
I have a Server class and a Timer inside it which is supposed to clear dead clients (clients who crashed). 我有一个Server类和一个Timer,它应该清除死客户端(崩溃的客户端)。 I followed the example below by locking the collection when the Timer iterates over the users but I still get this exception (after I crash a connected client).
我按照下面的示例通过在Timer迭代用户时锁定集合但我仍然得到此异常(在我崩溃连接的客户端之后)。
http://www.javaperformancetuning.com/articles/fastfail2.shtml http://www.javaperformancetuning.com/articles/fastfail2.shtml
List<User> users;
List<User> connectedUsers;
ConcurrentMap<User, IClient> clients;
...
users = Collections.synchronizedList(new ArrayList<User>());
connectedUsers = new ArrayList<User>();
clients = new ConcurrentHashMap<User, IClient>();
timer = new Timer();
timer.schedule(new ClearDeadClients(), 5000, 5000);
...
class ClearDeadClients extends TimerTask {
public void run() {
synchronized (users) {
Iterator<User> it = users.iterator();
while (it.hasNext()) {
User user = it.next(); // Throws exception
if (!connectedUsers.contains(user)) {
users.remove(user);
clients.remove(user);
}
}
}
connectedUsers.clear();
}
}
You need to remove from the iterator not the collection. 您需要从迭代器中删除而不是集合。 It would look like this instead:
它看起来像这样:
Iterator<User> it = users.iterator();
while (it.hasNext()) {
User user = it.next();
if (!connectedUsers.contains(user)) {
it.remove();
clients.remove(user);
}
}
You cannot modify a collection while iterating over it - unfortunately you do that here with users
, and the ConcurrentModificationException is the result. 迭代时无法修改集合 - 不幸的是,您在此处与
users
一起执行此users
,并且结果是ConcurrentModificationException。 From ArrayList's own javadocs : 从ArrayList自己的javadocs :
The iterators returned by this class's
iterator
andlistIterator
methods are fail-fast : if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's ownremove
oradd
methods, the iterator will throw aConcurrentModificationException
.此类的
iterator
和listIterator
方法返回的iterator
是快速失败的 :如果在创建迭代器之后的任何时候对列表进行结构修改,除了通过迭代器自己的remove
或add
方法之外,迭代器将抛出ConcurrentModificationException
。 Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.因此,在并发修改的情况下,迭代器快速而干净地失败,而不是在未来的未确定时间冒着任意的,非确定性行为的风险。
To fix this particular situation, you could instead use the Iterator's own remove()
method, by replacing this line: 要解决这种特殊情况,您可以使用Iterator自己的
remove()
方法替换此行:
users.remove(user);
with 同
it.remove();
This latter operation removes from the collection the last element that the iterator returned. 后一个操作从集合中删除迭代器返回的最后一个元素。 (This usage avoids the exception because the iterator is aware of the change and is able to ensure it's safe; with external modifications the iterator has no way to know whether the state of its traversal is still consistent, and so fails fast).
(这种用法避免了异常,因为迭代器知道更改并且能够确保它是安全的;通过外部修改,迭代器无法知道其遍历的状态是否仍然一致,因此快速失败)。
In some situations, this immediate removal may not be workable, in which case there are three alternative general approaches: 在某些情况下,这种立即删除可能不可行,在这种情况下,有三种可选的一般方法:
users
in this case), iterate over the copy and remove elements from the original . users
),遍历副本并从原始元素中删除元素。 List
implementation which can deal with concurrent modifications, like the CopyOnWriteArrayList List
实现,例如CopyOnWriteArrayList This is quite a common question - see also (for example) the loop on list with remove question for other answers. 这是一个非常常见的问题 - 另请参阅(例如) 列表中的循环,并删除其他答案的问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.