迭代Map时出现ConcurrentModificationException

时间:2013-07-17 07:24:22

标签: java android map concurrency iteration

我在下面有以下代码

Map<String, Integer> buyingItemEnumerationMap = this.toBuyItemEnumeration;
for (Entry<String, Integer> item : buyingItemEnumerationMap.entrySet()) {
   if(RandomEngine.boolChance(50)){ //will delete?
    buyingItemEnumerationMap.remove(item.getKey());
   }
   if(buyingItemEnumerationMap.size() == 1){
    break;
   }
}

现在我正在使用Android游戏,上面的代码以多线程方式运行。现在我有一个java.util.ConcurrentModificationException的例外。我已经研究过如何解决这个问题,但似乎没有对我有所帮助。  我在上面的代码上做的是随机删除一个条目。我怎样才能在那里实现它?

4 个答案:

答案 0 :(得分:9)

除非您使用Iterator,否则在迭代时无法从集合中删除元素。

这就是引起异常的原因。

buyingItemEnumerationMap.remove(item.getKey());

使用Iterator#remove()删除元素,同时迭代您的集合,如

Iterator<Map.Entry<String, Integer>> iterator = 
                           buyingItemEnumerationMap.entrySet().iterator();
while (iterator.hasNext()) {
   Map.Entry<String, Integer> item = iterator.next();
   if(RandomEngine.boolChance(50)){ //will delete?
      iterator.remove();
   }
   //..
}

编辑 :(回应OP的评论)
是的,通过Iterator#remove()HashMap.entrySet()返回的Set进行的删除将反映在基础Map中,因为Set由其支持。在这里引用JavaDoc:

  

返回此映射中包含的映射的Set视图。该集由地图支持,因此对地图的更改将反映在集中,反之亦然

答案 1 :(得分:6)

使用Iterator

Iterator<Map.Entry<String, Integer>> iter = this.toBuyItemEnumeration;
while (iter.hasNext()) {
    Map.Entry<String, Integer> entry = iter.next();
    if (some-condition){
        iter.remove();
    }
}

如何运作?

ConcurrentModificationException的javadoc说:

如果单个线程发出违反对象合同的一系列方法调用,则该对象可能会抛出此异常。例如,如果线程在使用失败快速迭代器迭代集合时直接修改集合,则迭代器将抛出此异常。

字段int expectedModCount被启动为等于字段protected transient int modCount = 0;(这对于集合和地图有效),modCount会跟踪对象的结构修改。如果迭代某点的modCount不等于expectedModCount,则会抛出ConcurrentModificationException

使用Iterator对地图/集合进行结构更改(如删除元素),我们确保删除操作将正确执行,例如modCount将等于expectedModCount

答案 2 :(得分:0)

在forEach循环中使用iterator并使用iterator.remove();

答案 3 :(得分:0)

you can't delete entries in a Map while traversing it by it's own property。不同的方法。