处理HashMap时出现ConcurrentModificationException

发布于 2024-10-18 03:56:15 字数 1607 浏览 2 评论 0 原文

我试图将 HashMap> 放入我的 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>(oldHashMap) 制作副本。我可以尝试解决此问题的其他常见方法吗?

编辑:我知道 ConcurrentModificationExceptions 的一般原因。仅当您可以帮助我理解为什么 Freemarker 框架抛出这些异常时才回复,好吗? =)

谢谢!

I'm trying to put a HashMap<Object, List<Object>> into my dataModel, but when i call the template.process() method, I get the following exception:

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)

After looking over some articles and older questions, I've tried to use a ConcurrentHashMap instead, to the same result. I've also tried making a copy using new HashMap<Object, List<Object>>(oldHashMap). Are there any other common fixes to this problem I could try?

EDIT: I know the general cause of ConcurrentModificationExceptions. Please only reply if you can help me understand why the framework Freemarker is throwing these exceptions, mkay? =)

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

没︽人懂的悲伤 2024-10-25 03:56:15

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);

The ConcurrentModificationException is caused by using an invalid iterator after the underlying collection has been changed. The only way to fix this is not changing the collection you are iterating over. In most cases this is not caused by multi-threading.

Simple Example:

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

fix 1, not supported by all iterators:

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

fix 2:

List<String> toRemove = ...;
for(String s: list){
   toRemove.add(s);
}
list.removeAll(toRemove);
月亮坠入山谷 2024-10-25 03:56:15

该异常意味着,当您迭代地图时,某些内容已更改地图的内容。

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

在我们了解到底是什么原因导致问题以及所需的行为是什么之前,很难就如何最好地解决问题提供建议。

The exception means that, while you're iterating over the map, something has changed the map's contents.

Your best course of action is figure out what that "something" is. For example, it could be another thread, or it could be that you have a foreach loop and modify the map from within the loop.

It is very hard to give advice on how to best fix the problem until we understand what exactly is causing it and what the desired behaviour is.

最美不过初阳 2024-10-25 03:56:15

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

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

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

TreeMap 的 Java API 这里

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

请注意,
不能保证迭代器,因为它
一般来说,是不可能的
做出任何硬性保证
存在不同步并发
修改。快速失败迭代器
抛出并发修改异常
在尽最大努力的基础上。因此,它
编写一个程序是错误的
依赖于这个例外
正确性:快速失败行为
迭代器应该仅用于
检测错误。

You'll get this kind of problem on List and Map when doing something like this:

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

The same goes with maps. The solution is to look for possible places where you might be modifying the map inside the loop over that map. Or if you are using a multi-threaded application, then it's possible that another thread is looping over the map while you are modifying it (or visa-versa). In such case you'll need to synchronize access to the map in both places: looping code and map modifying code.

There some info on it in the Java API for TreeMap here.

The iterators returned by the iterator
method of the collections returned by
all of this class's "collection view
methods" are fail-fast: if the map is
structurally modified at any time
after the iterator is created, in any
way except through the iterator's own
remove method, the iterator will throw
a ConcurrentModificationException.
Thus, in the face of concurrent
modification, the iterator fails
quickly and cleanly, rather than
risking arbitrary, non-deterministic
behavior at an undetermined time in
the future.

Note that the fail-fast behavior of an
iterator cannot be guaranteed as it
is, generally speaking, impossible to
make any hard guarantees in the
presence of unsynchronized concurrent
modification. Fail-fast iterators
throw ConcurrentModificationException
on a best-effort basis. Therefore, it
would be wrong to write a program that
depended on this exception for its
correctness: the fail-fast behavior of
iterators should be used only to
detect bugs.

漆黑的白昼 2024-10-25 03:56:15

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

Synchronise access to the hashmap so that only one thread can be accessing the hashmap at once.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文