0

我有一个 ClientSocket 和客户端对象的 HashMap。

我正在使用 for 循环迭代抛出它们,但有时会在哈希图中添加新行,然后我得到 java.util.ConcurrentModificationException 错误。我完全理解它为什么会发生,但我不明白如何解决它。我试图在迭代开始之前制作我的 HashMap 的新副本,但是 - 我仍然得到错误。

我的代码:

private volatile HashMap<ClientSocket, Client> clientsMap = new HashMap<ClientSocket, Client>();
private volatile HashMap<ClientSocket, Client> iteratorClientsMap = new HashMap<ClientSocket, Client>();
private volatile ClientsMapIterator iterator;

iterator = new ClientsMapIterator(clientsMap);
iteratorClientsMap = iterator.getItreator();

for (Map.Entry<ClientSocket, Client> entry : iteratorClientsMap.entrySet()) {                                                                   
    ClientSocket key = entry.getKey();
    //Client value = entry.getValue();              
    long diff = currentTime - key.getLastOnline();
    boolean isAvailable = false;

    try {
        isAvailable = (key.getSocket().getInputStream().available() > 0);
    } catch (IOException e) {
        e.printStackTrace();
    }               

    if ( diff > keepAlive)              
        removeClientSocket(key);
}

public synchronized void addClientSocket(ClientSocket clientSocket) {
    clientsMap.put(clientSocket, null);                 
}

addClientSocket 是因为它我得到错误的函数。

4

3 回答 3

2

您在迭代集合时正在修改集合。这被标记为并发修改。

最简单的解决方案是使用不会触发 CME 的 ConcurrentHashMap。

于 2012-05-13T13:14:13.523 回答
0

我找到了一个我不知道它是否是最好的解决方案:

synchronized (this) {
            iterateClientsMap = new HashMap<ClientSocket, Client>(clientsMap);  
        }           

        for (Map.Entry<ClientSocket, Client> entry : iterateClientsMap.entrySet())      
        {                                                                                                   
            ClientSocket key = entry.getKey();
            //Client value = entry.getValue();              
            long diff = currentTime - key.getLastOnline();
            boolean isAvailable = false;
            try {
                isAvailable = (key.getSocket().getInputStream().available() > 0);
            } catch (IOException e) {
                e.printStackTrace();
            }               
            if ( diff > keepAlive)              
                removeClientSocket(key);
}

我已经复制了我的 HashMap 并在副本上对其进行了迭代,并且在每个迭代过程之前,我将它阻塞到其他线程(使用同步标题),因此它不会在复制过程中被中断

于 2012-05-13T14:12:35.873 回答
0

这个问题似乎从removeClientSocket(key);

似乎集合也在被迭代时被修改。

解决此问题的一种方法是将迭代器传递给此方法

removeClientSocket(iterator, key);

通过调用iterator.remove()而不是在迭代过程中从集合本身中删除来从该迭代器中删除键。

似乎您的问题出在多个线程上,或者您对同一锁的添加和删除同步访问,例如:

public void removeClientSocket(iterator, key){
    synchronized(clientMap){
      //now remove
    }
}

public void addClientSocket(ClientSocket clientSocket) {
    synchronized(clientsMap){
        clientsMap.put(clientSocket, null);    
    }             
}

或使用 java.util.Concurrent 包进行自动并发控制。您可以专门使用ConcurrentHashMap.

于 2012-05-13T14:16:10.493 回答