处理HashMap时出现ConcurrentModificationException

时间:2011-02-21 10:59:18

标签: freemarker

我正在尝试将HashMap <Object, List<Object>>放入我的dataModel中,但是当我调用template.process()方法时,我得到以下异常:

java.util.ConcurrentModificationException
    at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
    at java.util.HashMap$KeyIterator.next(HashMap.java:828)
    at freemarker.template.SimpleCollection$SimpleTemplateModelIterator.next(SimpleCollection.java:142)
    at freemarker.core.IteratorBlock$Context.runLoop(IteratorBlock.java:157)
    at freemarker.core.Environment.visit(Environment.java:351)
    at freemarker.core.IteratorBlock.accept(IteratorBlock.java:95)
    at freemarker.core.Environment.visit(Environment.java:196)
    at freemarker.core.MixedContent.accept(MixedContent.java:92)
    at freemarker.core.Environment.visit(Environment.java:196)
    at freemarker.core.IteratorBlock$Context.runLoop(IteratorBlock.java:172)
    at freemarker.core.Environment.visit(Environment.java:351)
    at freemarker.core.IteratorBlock.accept(IteratorBlock.java:95)
    at freemarker.core.Environment.visit(Environment.java:196)
    at freemarker.core.MixedContent.accept(MixedContent.java:92)
    at freemarker.core.Environment.visit(Environment.java:196)
    at freemarker.core.Environment.process(Environment.java:176)
    at freemarker.template.Template.process(Template.java:232)

在查看了一些文章和旧问题之后,我尝试使用ConcurrentHashMap来获得相同的结果。我也尝试使用new HashMap<Object, List<Object>>(oldHashMap)制作副本。我可以尝试解决这个问题吗?

编辑:我知道ConcurrentModificationExceptions的一般原因。请回复一下,如果你能帮我理解为什么Freemarker框架会抛出这些例外,mkay? =)

谢谢!

4 个答案:

答案 0 :(得分:3)

ConcurrentModificationException是在更改基础集合后使用无效迭代器引起的。解决这个问题的唯一方法就是不要改变你正在迭代的集合。在大多数情况下,这不是由多线程引起的。

简单示例:

//throws an exception in the second iteration
for(String s: list){
   list.remove(s);//changes the collection
}

修复1,并非所有迭代器都支持:

Iterator<String> iter = list.iterator();
while(iter.hasNext()){
    iter.next();
    iter.remove();//iterator still valid
} 

修复2:

List<String> toRemove = ...;
for(String s: list){
   toRemove.add(s);
}
list.removeAll(toRemove);

答案 1 :(得分:0)

异常意味着,当您在地图上进行迭代时,某些内容已经改变了地图的内容。

你最好的行动方案是找出那些“东西”是什么。例如,它可能是另一个线程,或者可能是您有一个foreach循环并从循环内修改映射。

很难就如何最好地解决问题提出建议,直到我们明白究竟是什么导致问题以及所期望的行为是什么。

答案 2 :(得分:0)

在执行此类操作时,您会在ListMap上遇到此类问题:

List<A> list = ...; //a list with few elements
for(A anObject : list){
  list.add(anotherObject); //modify list inside the loop
}

地图也是如此。解决方案是寻找可能在地图上循环内修改地图的地方。或者,如果您使用的是多线程应用程序,那么在您修改它时,另一个线程可能会在地图上循环(反之亦然)。在这种情况下,您需要在两个位置同步对地图的访问:循环代码和地图修改代码。

TreeMap here的Java API中有一些信息。

  

迭代器返回的迭代器   返回的集合的方法   所有这个类的“集合视图   方法“快速失败:如果地图是   随时进行结构修改   在迭代器创建之后,任何一个   除了通过迭代器自己的方式   删除方法,迭代器将抛出   一个ConcurrentModificationException。   因此,面对并发   修改,迭代器失败   快速而干净,而不是   冒着任意,不确定的风险   在一个不确定的时间的行为   未来。

     

注意一个快速失败的行为   迭代器无法保证   一般来说,是不可能的   做出任何艰难的保证   存在未同步的并发   修改。失败快速的迭代器   抛出ConcurrentModificationException   尽力而为。因此,它   写一个程序是不对的   依赖于这个例外   正确性:失败的快速行为   迭代器应该只用于   检测错误。

答案 3 :(得分:-1)

同步对hashmap的访问,以便一次只能有一个线程访问hashmap。