我的代码不断出现并发修改异常。我只是迭代 HashMap 并修改值。通过研究,我发现人们说要使用迭代器和 iterator.remove 等。我尝试用它来实现,但仍然不断收到错误。我想也许多个线程访问它? (虽然在我的代码中这个 block 只在一个线程中运行)所以我把它放在一个同步块(synchronized block)中。但是,我仍然收到错误......
Map map= Collections.synchronizedMap(questionNumberAnswerCache);
synchronized (map) {
for (Iterator<Map.Entry<String, Integer>> it = questionNumberAnswerCache.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<String, Integer> entry = it.next();
if (entry.getKey() == null || entry.getValue() == null) {
continue;
} else {
try {
Question me = Question.getQuery().get(entry.getKey());
int i = Activity.getQuery()
.whereGreaterThan(Constants.kQollegeActivityCreatedAtKey, lastUpdated.get("AnswerNumberCache " + entry.getKey()))
.whereEqualTo(Constants.kQollegeActivityTypeKey, Constants.kQollegeActivityTypeAnswer)
.whereEqualTo(Constants.kQollegeActivityQuestionKey, me)
.find().size();
lastUpdated.put("AnswerNumberCache " + entry.getKey(), Calendar.getInstance().getTime());
int old_num = entry.getValue();
entry.setValue(i + old_num);
} catch (ParseException e) {
entry.setValue(0);
}
}
}
}
错误:
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:787)
at java.util.HashMap$EntryIterator.next(HashMap.java:824)
at java.util.HashMap$EntryIterator.next(HashMap.java:822)
at com.juryroom.qollege_android_v1.QollegeCache.refreshQuestionAnswerNumberCache(QollegeCache.java:379)
at com.juryroom.qollege_android_v1.QollegeCache.refreshQuestionCaches(QollegeCache.java:267)
at com.juryroom.qollege_android_v1.UpdateCacheService.onHandleIntent(UpdateCacheService.java:28)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.os.HandlerThread.run(HandlerThread.java:61)
最佳答案
发生了什么:
迭代器正在遍历映射。 map 实际上并不像列表,因为它不关心顺序。因此,当您向 map 添加某些内容时,它可能会插入到中间、您已经循环遍历的对象中间的某个位置、末尾等。因此,它不会给您随机行为,而是会失败。
您的解决方案:
同步映射和同步块(synchronized block)允许您同时有两个线程运行。它在这里并没有真正的帮助,因为问题是同一个线程正在以非法的方式修改它。
你应该做什么:
您可以只保存要修改的键。使用键和新值制作映射不会成为问题,除非这是一段非常耗时的代码。
然后,您只需迭代 newValues 映射并更新 oldValues 映射即可。由于您没有迭代正在更新的 map ,所以这不是问题。
或者您可以简单地迭代键(对于 String s : yourMap),然后查找您想要更改的值。由于您只是迭代键,因此您可以随意更改值(但不能删除值)。
您还可以尝试使用 ConcurrentHashMap,它应该允许您修改它,但行为未定义,因此这是有风险的。仅更改值不应导致问题,但如果添加或删除,您永远不知道它最终是否会被迭代。
关于java - Android:Hashmap并发修改异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32648687/