Lig*_*rce 4 java client arraylist concurrentmodification
我有一个Server类和一个Timer,它应该清除死客户端(崩溃的客户端).我按照下面的示例通过在Timer迭代用户时锁定集合但我仍然得到此异常(在我崩溃连接的客户端之后).
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();
}
}
Run Code Online (Sandbox Code Playgroud)
Joh*_*int 11
您需要从迭代器中删除而不是集合.它看起来像这样:
Iterator<User> it = users.iterator();
while (it.hasNext()) {
User user = it.next();
if (!connectedUsers.contains(user)) {
it.remove();
clients.remove(user);
}
}
Run Code Online (Sandbox Code Playgroud)
迭代时不能修改集合 - 不幸的是你在这里做了users,并且结果是ConcurrentModificationException.从ArrayList自己的javadocs:
这个类
iterator和listIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时候对列表进行结构修改,除了通过迭代器自己remove或add方法之外,迭代器将抛出一个ConcurrentModificationException.因此,在并发修改的情况下,迭代器快速而干净地失败,而不是在未来的未确定时间冒任意,非确定性行为的风险.
要解决这种特殊情况,您可以使用Iterator自己的remove()方法替换此行:
users.remove(user);
Run Code Online (Sandbox Code Playgroud)
同
it.remove();
Run Code Online (Sandbox Code Playgroud)
后一个操作从集合中删除迭代器返回的最后一个元素.(这种用法避免了异常,因为迭代器知道更改并且能够确保它是安全的;通过外部修改,迭代器无法知道其遍历的状态是否仍然一致,因此快速失败).
在某些情况下,这种立即删除可能不可行,在这种情况下,有三种可选的一般方法:
users在本例中),遍历副本并从原始元素中删除元素.List可以处理并发修改的实现,例如CopyOnWriteArrayList这是一个非常常见的问题 - 另请参阅(例如)列表中的循环,并删除其他答案的问题.
| 归档时间: |
|
| 查看次数: |
9756 次 |
| 最近记录: |