2012-05-13 2 views
0

У меня есть HashMap ClientSocket и Клиентский объект.Итерация/удаление 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

Показать код '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

Вы изменяете сборку, итерации по ней. Это помечено как одновременная модификация.

Простейшим решением является использование ConcurrentHashMap, которое не вызывает CME.

+0

, когда я изменил его на ConcurrentHashMap, я получаю java.lang.NullPointerException в java.util.concurrent.ConcurrentHashMap.put при попытке добавить новую строку к карте. Почему мое дублирование не является хорошим (и не работает)? Я копирую текущий hashmap и итерацию на копии вместо origina –

+0

Вы не можете добавить значение значения в ConcurrentHashMap. Почему вы устанавливаете его на «null», когда вы называете метод addXxxx? Возможно, вы можете предоставить реальный объект? –

+0

Я передаю только значение как null, ключ задан. Это действительно очень важно, он сделает для меня differenece позже, если у клиента есть объект Client (что означает, что он был зарегистрирован) или нет ... –

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.

Смежные вопросы