2012-05-13 41 views
0

我有一個ClientSocket和Client對象的HashMap。HashMap迭代/刪除獲取java.util.ConcurrentModificationException

我是迭代使用循環扔,但有時新行添加到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

當我將它更改爲ConcurrentHashMap時,顯示'removeClientSocket'的代碼 – assylias

回答

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

您正在修改集合,同時迭代它。這被標記爲併發修改。

最簡單的解決方案是使用不觸發CME一個的ConcurrentHashMap。

+0

當嘗試向地圖添加新行時,我在java.util.concurrent.ConcurrentHashMap.put中得到java.lang.NullPointerException。 爲什麼我的重複不好(也沒有工作)?我正在複製當前的散列表並在副本上迭代而不是原始地址 –

+0

您無法將值值添加到ConcurrentHashMap。當你的方法被稱爲addXxxx時,爲什麼你將它設置爲'null'?也許你可以提供一個實際的對象? –

+0

我傳遞只有一個空值,將鍵值設爲.. 它實際上是非常重要的,它會使differenece我以後如果客戶有一個客戶對象(這意味着他已經登錄)或不... –

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