2017-05-30 5 views
1

Ich erhalte ConcurrentModificationException und ich weiß nicht, wie es zu beheben.HashMap Iterator ConcurrentModificationException

Ich habe ein Android Multithread-Anwendung (mit Sockeln zu kommunizieren), und ich bin Callbacks (Schnittstelle) in eine hashmap speichert.

public class ApiManager { 

    private static ApiManager instance; 

    public synchronized ApiManager getInstance() { 
     if (instance == null) 
     instance = new ApiManager(); 

     return instance; 
    } 

    private final HashMap<String, Callback> callbacks = new HashMap<>; 

    // Setters and getters for storing callbacks 

    private @Nullable Callback getCallback(@NoNull String key) { 
     synchronized (callbacks) { 
     return callbacks.get(key); 
     } 
    } 

    private void addCallback(@NonNull String key, @NonNull Callback callback) { 
     synchronized (callbacks) { 
     callbacks.put(key, callback); 
     } 
    } 

    private void removeCallback(@NonNull String key) { 
     synchronized (callbacks) { 
      callbacks.remove(key); 
     } 
    } 

    // Request to retrieve the user's profile from server 
    public synchronized void getProfile(String key, Callback callback) { 
     // Save the callback 
     addCallback(key, callback); 

     // Do the asynchronous request 
     getSocket().emit("getProfile", new Ack() { 
     @Override 
     public void call(Object... args) { 
      // Deliver the response 
      Callback callback = getCallback(key); 
      if (callback != null) 
       callback.onResponse(args); 

      // Remove the callback 
      removeCallback(key);     
     } 
     }); 
    } 

    // Called when the socket disconnects 
    // ----> This is the method where I get the exception ! 
    private void onSocketDisconnect() { 

     /* 
     * Notify stored callbacks that the socket has disconnected 
     */ 

     synchronized (callbacks) { 
     Set<Map.Entry<String, Callback>> set = callbacks.entrySet(); 
     if (set.size() > 0) { 
      Iterator<Map.Entry<String, Callback>> iterator = set.iterator(); 
      while (iterator.hasNext()) { 
       // This is the line where the exception occurres 
       Map.Entry<String, Callback> entry = iterator.next(); 

       String key = entry.getKey(); 
       Callback callback = entry.getValue(); 

       if (callback != null) { 
        // Notify callback that there was a socket disconnect exception 
       callback.onResponse(Factory.buildResponseFailure(SOCKET_DISC)); 

        it.remove(); 
       } 
      } 
     } 
     } 
    } 
} 

Und manchmal eine Ausnahme occurres:

Exception: java.util.ConcurrentModificationException 
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:851) 
     at java.util.HashMap$EntryIterator.next(HashMap.java:891) 
     at java.util.HashMap$EntryIterator.next(HashMap.java:890) 

Dies ist, wie ich das Profil des Benutzers abrufen:

ApiManager.getInstance().getProfile(KEY_PROFILE_REQ, new Callback() { 
    @Override 
    public void onResponse(Object... args) { 
     // Parsing the data 
    } 
}); 

Wie Sie bin ich Zugriff auf die hashmap in einem synchronized Block sehen . Die Klasse ApiManager ist ein Singleton. Warum erhalte ich eine ConcurrentModificationException, wenn ich das Objekt während der Iteration sperre? Wie erhalten andere Threads die Sperre? Fehle ich etwas?

Hinweis: In diesem Beispiel sind drei Fäden. UI-Thread (wo ich die getProfile() -Methode aufrufen), der zweite Thread ist der innere Thread des Sockets (Lieferungsantwort) und ein anderer Thread, der die onSocketDisconnected()-Methode aufruft.

+0

In Ihrem while (iterator.hasNext()) Bausteinaufruf iterator.remove nach Daten zugreifen. –

+0

https://examples.javacodegeeks.com/java-basics/exceptions/java-util-concurrentmodificationexception-how-to-handle-concurrent-modification-exception/ – Stallion

Antwort

0

Das Entfernen eines Elements aus einer Sammlung während der Iteration über dasselbe könnte dies verursachen. Haben Sie versucht, die zu entfernenden Objekte irgendwo zu speichern und, nachdem Sie das letzte Element bearbeitet haben, set.removeAll (irgendwo)?

Verwandte Themen