ArrayList 上的 java.util.ConcurrentModificationException
我有一个服务器类和一个计时器,它应该清除死客户端(崩溃的客户端)。我按照下面的示例,在计时器迭代用户时锁定集合,但我仍然遇到此异常(在我使连接的客户端崩溃之后)。
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();
}
}
I have a Server class and a Timer inside it which is supposed to clear dead clients (clients who crashed). 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).
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();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您需要从迭代器而不是集合中删除。它看起来像这样:
You need to remove from the iterator not the collection. It would look like this instead:
您无法在迭代集合时对其进行修改 - 不幸的是,您在这里使用
users
进行了修改,结果是 ConcurrentModificationException。来自 ArrayList 自己的 javadocs:要修复这种特殊情况,您可以使用迭代器自己的
remove()
方法,方法是将这一行替换为:。
后一个操作将从集合中删除迭代器返回的最后一个元素 (这种用法避免了异常,因为迭代器知道更改并能够确保其安全;通过外部修改,迭代器无法知道其遍历的状态是否仍然一致,并且所以很快就会失败)。
在某些情况下,这种立即删除可能行不通,在这种情况下,存在三种替代的通用方法:
users
),迭代副本< /em> 并从原始内容中删除元素。List
实现,例如 CopyOnWriteArrayList这是一个相当常见的问题 - 另请参阅(例如)循环删除列表问题以获取其他答案。
You cannot modify a collection while iterating over it - unfortunately you do that here with
users
, and the ConcurrentModificationException is the result. From ArrayList's own javadocs:To fix this particular situation, you could instead use the Iterator's own
remove()
method, by replacing this line:with
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.List
implementation which can deal with concurrent modifications, like the CopyOnWriteArrayListThis is quite a common question - see also (for example) the loop on list with remove question for other answers.