2012-05-13 14 views
0

私はClientSocketとClient ObjectのHashMapを持っています。java.util.ConcurrentModificationExceptionを取得する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は、私はエラーを取得しています、それのための機能です。

+0

ConcurrentHashMapに変更したときに 'removeClientSocket'のコードを表示 – assylias

答えて

0

は、私はそれが最高のものであれば、私は知らない解決策を見つけましたそのほかのスレッド(同期タイトルを使用して)へので、問題は、あまりにも反復されている間、コレクションが変更されているようだremoveClientSocket(key);

から伝播しているように見えるコピー

2

コレクションの反復処理中にコレクションを変更しています。これは並行変更としてフラグが立てられます。

最も簡単な解決策は、CMEをトリガーしないConcurrentHashMapを使用することです。

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を複製してコピーでそれを繰り返してきたが、各反復処理の前に、私がブロックしています:

+0

私はjava.util.concurrent.ConcurrentHashMap.putでjava.lang.NullPointerExceptionを取得します。新しい行をマップに追加しようとしています。 なぜ私の複製はうまくいかないのですか?私は現在のハッシュマップをコピーして、元のコピーではなくコピーを反復しています –

+0

ConcurrentHashMapに値の値を追加することはできません。なぜあなたはメソッドがaddXxxxと呼ばれるとき、それを 'null'に設定していますか?おそらくあなたは実際のオブジェクトを提供することができますか? –

+0

私はnullとして値を渡している、キーが設定されている.. 実際にはかなり重要です、クライアントがクライアントオブジェクト(彼がログインしていたことを意味する)を持っている場合、後で私のためにdiffereneceを行います... –

0

中に中断されることはありません。この問題を解決する

一つの方法は、しばらくの繰り返しの中で自分自身をiterator.remove()を呼び出す代わりに、コレクションから削除することによって、このイテレータからキーを削除し、この方法

removeClientSocket(iterator, key); 

にイテレータを渡しています。

一見あなたの問題のような同じロックを追加および削除の両方に自分の同期アクセスのいずれか、複数のスレッドを使用することです:

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

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

かのためにjava.util.concurrentパッケージを使用するには自動並行制御。具体的にはConcurrentHashMapを使用できます。

関連する問題