6

我正在使用以下构造来创建 threadsafe Map

Collections.synchronizedMap(new LinkedHashMap());

虽然我遇到了ConcurrentModificationException错误。

4

5 回答 5

8

没有代码很难猜出真正的问题是什么,但我的猜测是,您没有使用返回的集合来执行操作。根据javadoc

为了保证串行访问,对后备集合的所有访问都是通过返回的集合完成的,这一点至关重要。当迭代它时,用户必须手动同步返回的集合:

  Collection c = Collections.synchronizedCollection(myCollection);
     ...
  synchronized(c) {
      Iterator i = c.iterator(); // Must be in the synchronized block
      while (i.hasNext())
         foo(i.next());
  }

不遵循此建议可能会导致不确定的行为。

于 2012-10-31T04:14:43.240 回答
5

不要贬低这里的任何其他答案,但下面的代码表明并发修改与实际的多线程几乎没有关系。当您说迭代集合但在迭代时对其进行修改时会引起这种情况......

  List list = new ArrayList();
  list.add("1");
  list.add("2");

  Iterator i = list.iterator();
  while (i.hasNext()) {
      Object value = i.next();  // throws java.util.ConcurrentModificationException

      list.add("another");  
  }
于 2012-10-31T05:03:12.517 回答
2

长话短说,ConcurrentModificationException在您的代码中不包含 a 的解决方案是使用 aConcurrentHashMap而不是Collections.synchronizedMap(new LinkedHashMap());. 这里的解释:

正如 Nambari 所说,如果没有实际代码,问题就更难识别。请注意,这Map仅保护包含的对象。不过,您可以在方法中修改相同的对象实例:

Map<String, Object> map = new ConcurrentHashMap<String, Object();
//fill the map...
map.put("data", new Data());

//and now we have this unsynchronized method that two or more threads can access at the same time
public void modifyData(String key, int newDataIntValue) {
    //this is synchronized by the ConcurrentHashMap
    Data data = map.get(key);
    //this isn't
    //you can get problems here...
    data.setIntValue(newDataIntValue);
}

同步集合不会为这些情况保存您的代码。你应该自己同步这个方法。

附加信息:如果您正在尝试实现缓存库或享元设计模式,请不要重新发明轮子并使用经过验证和测试的框架,例如ehcachejboss cache

于 2012-10-31T04:30:18.647 回答
0

请找到java文档

返回由指定映射支持的同步(线程安全)映射。为了保证串行访问,对支持映射的所有访问都是通过返回的映射完成的,这一点至关重要。当迭代其任何集合视图时,用户必须在返回的地图上手动同步:

  Map m = Collections.synchronizedMap(new HashMap());
  ...
  Set s = m.keySet();  // Needn't be in synchronized block
  ...
  synchronized(m) {  // Synchronizing on m, not s!
      Iterator i = s.iterator(); // Must be in synchronized block
       while (i.hasNext())
          foo(i.next());
   }

不遵循此建议可能会导致不确定的行为。如果指定的映射是可序列化的,则返回的映射将是可序列化的。

参数: m 要“包装”在同步地图中的地图。返回: 指定地图的同步视图。

于 2012-10-31T04:17:42.287 回答
0

Synchronized 与 ConcurrentModificationException 无关,因为如果您在使用列表的 remove 方法迭代列表时尝试删除列表项,它可以在单线程环境中发生。

同步仅保证您的串行访问。

于 2015-08-07T06:44:42.253 回答