【问题标题】:ConcurrentModificationException even with IteratorConcurrentModificationException 即使使用迭代器
【发布时间】:2015-12-29 08:55:50
【问题描述】:

我正在使用 HashMap 并使用迭代器从地图中删除元素。

new Handler(SdkContext.getApplicationContext().getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                synchronized (this) {

                    Iterator<Map.Entry<Placement, Aunit>> iterator = map.entrySet().iterator();
                    while (iterator.hasNext()) {
                        Map.Entry<Placement, Aunit> entry = iterator.next();
                        entry.getValue().deInit();
                        iterator.remove();
                    }
                }
            }
        });

但即使是这段代码也只是有时会导致ConcurrentModificationException。它既是线程安全的,我也在使用Iterator。 那么怎么会导致异常呢?

【问题讨论】:

  • 您是否同时启动多个线程?尝试在 Map 而不是匿名 Runnable 类上同步。

标签: java android concurrency hashmap


【解决方案1】:

大多数集合/迭代器都不是线程安全的。 您似乎正试图通过致电synchronized 来解决这个问题。如果您使用相同的监视器对象同步每个对集合(您的map)的访问(读取和写入),这不是一个坏主意。

在您的示例代码中,您使用this 作为监视器/锁定对象(指的是Runnable 类型的匿名内部类的实例)。这是不合适的,因为您在其他地方操作集合时没有使用相同的对象:this 每次调用代码时都是不同的对象,并且不会交给调用代码。

因此,要正确执行此操作,您必须同步每个map 的访问。而且,您每次都必须使用相同的同步对象(您可以使用map 本身)。您可能还想了解同步的真正工作原理。

【讨论】:

  • 好的。但是如果我使用顶级类的this 来同步HashMap 上的每个修改操作,那么它不应该抛出异常。对吗?或者 ConcurrentHashMap 也应该在这种情况下工作?
  • ConcurrentHashMap 应该可以工作。我不会使用顶级类的this,因为它会是相当粗糙的锁定。另外,坦率地说,我不知道您是否有该类的一个或多个实例。 ConcurrentHashMap 是更好的路线。
  • 好的。顺便说一句,那个类是一个单例类。
【解决方案2】:

在遍历地图时,我们不能通过添加或删除元素来改变地图的结构。在这里,您尝试从引发 ConcurrentModifactionException 的地图中删除元素。在这里,您可以获得 Runnable 对象上的同步,而不是地图上的同步。以下代码将为您提供同步地图,或者您可以使用提供的 ConcurrentMap。

   Collections.synchronizedMap(map)

【讨论】:

  • 我们当然可以使用迭代器进行结构修改。
  • A synchronizedMap 不会阻止一个线程在另一个线程循环遍历迭代器时进行修改。
猜你喜欢
  • 1970-01-01
  • 2018-10-21
  • 2014-05-23
  • 2017-11-11
  • 1970-01-01
  • 2012-11-21
  • 2018-05-18
  • 2023-03-10
  • 2013-09-26
相关资源
最近更新 更多