0

ClientSocket と Client Object の 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

問題は次から伝播しているようですremoveClientSocket(key);

コレクションも反復されている間に変更されているようです。

この問題を解決する 1 つの方法は、イテレータをこのメソッドに渡すことです。

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 に答える
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 に答える