java - Android:Hashmap并发修改异常

标签 java android multithreading hashmap concurrentmodification

我的代码不断出现并发修改异常。我只是迭代 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/

相关文章:

java - 无法将 View.getContext 强制转换为托管 Activity

android - 在 android 3.2 上的 actionbar 中搜索元素时,findViewById 返回 null

java - 使缓存失效并重新启动并不能修复 BR 导入错误...数据绑定(bind)问题

android - 如何根据语言环境显示日期格式?

java - 在它的关键部分执行的线程可以在 Java 中被抢占吗?

ios - 使用 NSThread 时未调用 NSURLConnectionDelegate 方法

java - 无法通过 Spring 加载数据库驱动程序,但可以在类路径中手动找到它

java - List Iterator的add()方法对迭代器做了什么?

java - 我如何在 Windows plaf 中接收组合框箭头图标

java - 同步块(synchronized block)是否会导致所有写缓存刷新?