HashMap迭代器ConcurrentModificationException

时间:2017-05-30 10:36:40

标签: android websocket hashmap concurrentmodification

我收到了ConcurrentModificationException,我不知道如何修复它。

我有一个Android多线程应用程序(与套接字通信),我将回调(接口)存储到一个hashmap中。

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

有时会发生异常:

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

正如您所看到的,我正在访问synchronized块中的hashmap。 ApiManager类是单身。如果我在迭代时锁定对象,为什么我会得到ConcurrentModificationException?其他线程如何获得锁定?我错过了什么吗?

注意:在这个例子中是3个线程。 UI线程(我称之为getProfile()方法),第二个线程是套接字的内部线程(传递响应),另一个线程调用onSocketDisconnected()方法。

1 个答案:

答案 0 :(得分:0)

在迭代过程中从集合中删除项目可能会导致此问题。您是否尝试过存储要删除的项目,然后在处理完最终元素后,set.removeAll(某处)?