ArrayList上的java.util.ConcurrentModificationException

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)


And*_*yle 9

迭代时不能修改集合 - 不幸的是你在这里做了users,并且结果是ConcurrentModificationException.从ArrayList自己的javadocs:

这个类iteratorlistIterator方法返回的迭代器是快速失败的:如果在创建迭代器之后的任何时候对列表进行结构修改,除了通过迭代器自己removeadd方法之外,迭代器将抛出一个ConcurrentModificationException.因此,在并发修改的情况下,迭代器快速而干净地失败,而不是在未来的未确定时间冒任意,非确定性行为的风险.

要解决这种特殊情况,您可以使用Iterator自己的remove()方法替换此行:

users.remove(user);
Run Code Online (Sandbox Code Playgroud)

it.remove();
Run Code Online (Sandbox Code Playgroud)

后一个操作从集合中删除迭代器返回的最后一个元素.(这种用法避免了异常,因为迭代器知道更改并且能够确保它是安全的;通过外部修改,迭代器无法知道其遍历的状态是否仍然一致,因此快速失败).

在某些情况下,这种立即删除可能不可行,在这种情况下,有三种可选的一般方法:

  1. 获取集合的副本(users在本例中),遍历副本并从原始元素中删除元素.
  2. 在迭代期间,构建一组要删除的元素,然后在迭代完成后执行批量删除.
  3. 使用List可以处理并发修改的实现,例如CopyOnWriteArrayList

这是一个非常常见的问题 - 另请参阅(例如)列表中循环,并删除其他答案的问题.

  • 要添加到列表中:3.使用`List`实现,它可以处理并发修改,如`CopyOnWriteArrayList`. (3认同)