并发修改异常 [英] Concurrent Modification Exception

查看:195
本文介绍了并发修改异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在处理多线程应用程序,我偶尔会收到一个同时修改异常(平均大约每小时一次或两次,但以看似随机的间隔出现)。



错误的类本质上是一个地图的包装器 - 它扩展 LinkedHashMap (accessOrder设置为true)。该类有以下几种方法:

 同步集(SomeKey键,SomeValue val)

set方法将键/值对添加到内部映射,并受synchronized关键字保护。

 同步get(SomeKey键)

get方法返回基于输入键的值。

  rebuild()

内部映射在一段时间内重建一次(〜每2分钟一次,间隔与异常不匹配)。重建方法基本上根据它们的键重建值。因为rebuild()相当昂贵,我没有在方法上放一个synchronized关键字。相反,我在做:

  public void rebuild(){
/ *初始化东西* /
List< SomeKey> keysCopy = new ArrayList< SomeKey>();
synchronized(this){
keysCopy.addAll(internalMap.keySet());
}
/ *
使用keysCopy做更新临时映射
* /
synchronized(this){
internalMap.putAll(tempMap);
}
}

异常发生在

  keysCopy.addAll(internalMap.keySet()); 

同步区块内。



建议非常感谢。随意指向我在有效的Java 和/或并发实践中的具体页面/章节。



更新1:



清除堆栈跟踪:

  java.util.ConcurrentModificationException 
at java.util.LinkedHashMap $ LinkedHashIterator.nextEntry(LinkedHashMap.java:365)
在java.util.LinkedHashMap $ KeyIterator.next(LinkedHashMap.java:376)
在java.util。 AbstractCollection.toArray(AbstractCollection.java:126)
at java.util.ArrayList.addAll(ArrayList.java:473)
at abcetc.SomeWrapper.rebuild(SomeWraper.java:109)
at abcetc.SomeCaller.updateCache(SomeCaller.java:421)
...

更新2:



感谢大家的答案。我认为问题在于LinkedHashMap及其accessOrder属性,尽管我不完全确定atm(调查)。



如果LinkedHashMap上的accessOrder设置为true,并且我访问它的keySet,然后继续通过addAll将一个keySet添加到一个linkedList,这些动作是否会改变顺序(即计数到一个访问)?


<如果你使用accessOrder = true构造LinkedHashMap,LinkedHashMap.get()实际上会改变LinkedHashMap,因为它将最近访问的条目存储在链接列表的前面。条目。也许有些东西在调用get(),而数组列表是用迭代器复制的。


I'm currently working on a multi-threaded application, and I occasionally receive a concurrently modification exception (approximately once or twice an hour on average, but occurring at seemingly random intervals).

The faulty class is essentially a wrapper for a map -- which extends LinkedHashMap (with accessOrder set to true). The class has a few methods:

synchronized set(SomeKey key, SomeValue val)

The set method adds a key/value pair to the internal map, and is protected by the synchronized keyword.

synchronized get(SomeKey key)

The get method returns the value based on the input key.

rebuild()

The internal map is rebuilt once in a while (~every 2 minutes, intervals do not match up with the exceptions). The rebuild method essentially rebuilds the values based on their keys. Since rebuild() is fairly expensive, I did not put a synchronized keyword on the method. Instead, I am doing:

public void rebuild(){
  /* initialization stuff */
  List<SomeKey> keysCopy = new ArrayList<SomeKey>();
  synchronized (this) {
    keysCopy.addAll(internalMap.keySet());
  }
  /* 
    do stuff with keysCopy, update a temporary map
   */    
  synchronized (this) {
    internalMap.putAll(tempMap);
  }
}

The exception occurs at

keysCopy.addAll(internalMap.keySet());

Inside the synchronized block.

Suggestions are greatly appreciated. Feel free to point me to specific pages/chapters in Effective Java and/or Concurrency in Practice.

Update 1:

Sanitized stacktrace:

java.util.ConcurrentModificationException
        at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(LinkedHashMap.java:365)
        at java.util.LinkedHashMap$KeyIterator.next(LinkedHashMap.java:376)
        at java.util.AbstractCollection.toArray(AbstractCollection.java:126)
        at java.util.ArrayList.addAll(ArrayList.java:473)
        at a.b.c.etc.SomeWrapper.rebuild(SomeWraper.java:109)
        at a.b.c.etc.SomeCaller.updateCache(SomeCaller.java:421)
        ...

Update 2:

Thanks everyone for the answers so far. I think the problem lies within the LinkedHashMap and its accessOrder attribute, although I am not entirely certain atm (investigating).

If accessOrder on a LinkedHashMap is set to true, and I access its keySet then proceed to add the keySet to a linkedList via addAll, do either of these actions mutate the order (i.e. count towards an "access")?

解决方案

If you constructed LinkedHashMap with accessOrder = true then LinkedHashMap.get() actually mutates the LinkedHashMap since it stores the most recently accessed entry at the front of the linked list of entries. Perhaps something is calling get() while the array list is making its copy with the Iterator.

这篇关于并发修改异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆