我有一个ClientSocket和客户端对象的HashMap。
我正在迭代使用for循环抛出它们,但有时新的行被添加到hashmap然后我得到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是因为它我得到错误的函数。
答案 0 :(得分:2)
您正在迭代它时修改集合。这被标记为并发修改。
最简单的解决方案是使用不触发CME的ConcurrentHashMap。
答案 1 :(得分: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并在副本上进行了迭代,在每次迭代过程之前,我将其阻塞到其他线程(使用同步标题),因此在复制过程中不会被中断
答案 2 :(得分: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
。