I am developing a timer manager that will allow multiple countdown timers and I cant seem to figure out how to avoid this ConcurrentModificationException. I have look at other peoples responses to similar problems but still cant figure it out.
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)
Actually your issue is not related to concurrency. Your Runnable
is always called from the same thread - the Main
thread, because you post it to Handler
.
ConcurrentModificationException
is thrown because you tries to modify collection inside for-each loop. That's fail-fast behaviour in order to protect non-thread-safe collections from potential concurrent modifications. You need to use Iterator
explicitly and call remove
at iterator object. Your "deletes invalid entries" part should look like this:
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();
}
}