2017-05-30 141 views
1

我得到ConcurrentModificationException,我不知道如何解決它。HashMap迭代器ConcurrentModificationException

我有一個Android多線程應用程序(與套接字通信),我存儲回調(接口)到一個哈希映射。

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(); 
       } 
      } 
     } 
     } 
    } 
} 

有時異常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) 

這是我如何獲取用戶的個人資料:

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

正如你可以看到我訪問的HashMap的​​塊。 ApiManager類是一個單例。如果我在迭代它的同時鎖定對象,爲什麼會得到ConcurrentModificationException?其他線程如何獲得鎖定?我錯過了什麼嗎?

注意:在這個例子中有3個線程。 UI線程(我稱之爲getProfile()方法),第二個線程是套接字的內部線程(傳遞響應),另一個線程調用onSocketDisconnected()方法。

+0

訪問數據後,在while(iterator.hasNext())塊中調用iterator.remove。 –

+0

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

回答

0

在迭代同一個集合時從集合中刪除一個項目可能會導致此問題。您是否嘗試過將要刪除的項目存儲在某處,然後在處理完最後一個元素後,set.removeAll(某處)?

相關問題