我正在开发一个允许多个倒计时器的计时器管理器,我似乎无法弄清楚如何避免这种ConcurrentModificationException。我看到其他人对类似问题的反应,但仍然无法弄明白。
mHandler = new Handler();
mUpdateUI = new Runnable() {
public void run() {
Iterator<HashMap.Entry<String, TimerHolder>> it = mTimers.entrySet().iterator();
while (it.hasNext()) {
-----------> Map.Entry<String, TimerHolder> pairs = it.next();
pairs.getValue().post();
}
Iterator<HashMap.Entry<String, TimerHolder>> iterator = mTimers.entrySet().iterator();
while (iterator.hasNext()) {
HashMap.Entry<String, TimerHolder> entry = iterator.next();
if (!entry.getValue().isValid()) {
iterator.remove();
}
}
mHandler.postDelayed(mUpdateUI, 1000); // 1 second
}
};
mHandler.post(mUpdateUI);
06-02 12:37:23.746: E/AndroidRuntime(10669): FATAL EXCEPTION: main
06-02 12:37:23.746: E/AndroidRuntime(10669): java.util.ConcurrentModificationException
06-02 12:37:23.746: E/AndroidRuntime(10669): at java.util.HashMap$HashIterator.nextEntry(HashMap.java:806)
06-02 12:37:23.746: E/AndroidRuntime(10669): at java.util.HashMap$EntryIterator.next(HashMap.java:843)
06-02 12:37:23.746: E/AndroidRuntime(10669): at java.util.HashMap$EntryIterator.next(HashMap.java:841)
06-02 12:37:23.746: E/AndroidRuntime(10669): at com.watcher.timer.TimerManager$1.run(TimerManager.java:57)
06-02 12:37:23.746: E/AndroidRuntime(10669): at android.os.Handler.handleCallback(Handler.java:730)
06-02 12:37:23.746: E/AndroidRuntime(10669): at android.os.Handler.dispatchMessage(Handler.java:92)
06-02 12:37:23.746: E/AndroidRuntime(10669): at android.os.Looper.loop(Looper.java:137)
06-02 12:37:23.746: E/AndroidRuntime(10669): at android.app.ActivityThread.main(ActivityThread.java:5493)
06-02 12:37:23.746: E/AndroidRuntime(10669): at java.lang.reflect.Method.invokeNative(Native Method)
06-02 12:37:23.746: E/AndroidRuntime(10669): at java.lang.reflect.Method.invoke(Method.java:525)
06-02 12:37:23.746: E/AndroidRuntime(10669): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1209)
06-02 12:37:23.746: E/AndroidRuntime(10669): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1025)
06-02 12:37:23.746: E/AndroidRuntime(10669): at dalvik.system.NativeStart.main(Native Method)
答案 0 :(得分:4)
实际上您的问题与并发性无关。您的Runnable
总是在同一个帖子中调用 - Main
主题,因为您将其发布到Handler
。
ConcurrentModificationException
是因为您尝试修改for-each循环内的集合。这是为了保护非线程安全集合免受潜在的并发修改而导致的快速失败行为。您需要显式使用Iterator
并在迭代器对象上调用remove
。你的&#34;删除了无效的条目&#34;部分看起来像这样:
Iterator<HashMap.Entry<String, TimerHolder>> iterator = mTimers.entrySet().iterator();
while (iterator.hasNext()) {
HashMap.Entry<String, TimerHolder> entry = iterator.next();
if (!entry.getValue().isValid()) {
iterator.remove();
}
}
答案 1 :(得分:0)
其他一些线程正在修改mTimers
地图,同时您的run()
方法正在迭代相同的地图。
解决此问题的一种可能(但不一定是最有效的)方法是将当前Map实例包装在同步映射中,并在任何地方使用包装对象:
Map mTimers = Collections.synchronizedMap(new HashMap(...));
同步映射将为您同步Map方法,因此一次只有一个线程可以使用Map。
但是,如果需要在单个原子事务中调用多个Map方法,则仍需要进行自己的同步。