14

I am calling function that returns TreeMap instance, and in the calling code I wanted to modify the TreeMap. However, I am getting a ConcurrentModificationException.

Here is my code:

public Map<String, String> function1() {
    Map<String, String> key_values = Collections.synchronizedMap(new TreeMap<String, String>());
    // all key_values.put() goes here

    return key_values;
}

And my calling code is:

Map<String, String> key_values =Collections.synchronizedMap(Classname.function1());
//here key_values.put() giving ConcurrentModificationException
4

5 回答 5

16

请注意,如果您使用迭代器,Collections.synchronizedMap它将永远不会保护您免受并发修改。此外,除非您Map从多个线程访问您的,否则创建同步地图是没有用的。没有被交给其他线程的局部范围的集合和变量不需要是synchronized.

我的猜测是,在您遗漏的代码中,您正在迭代, 或, 之一Map.entrySet,并在该迭代期间(在循环内)调用。使用您显示的代码,这是发生这种情况的唯一方法。Map.keySetMap.valuesput for

于 2012-12-18T06:47:29.030 回答
7

如果您使用ConcurrentSkipListMap可以更快并且没有这个问题。

public NavigableMap<String, String> function1() {
    NavigableMap<String, String> key_values = new ConcurrentSkipListMap<String, String>();
    // all key_values.put() goes here

    return key_values;
}

如果您不需要对键进行排序,则可以使用ConcurrentHashMap

于 2012-12-18T09:40:14.567 回答
1

您似乎正在获得同步地图的同步地图。如果我用它的内容(简化)替换对 function1() 的调用,我们有:

Map<String, String> key_values =Collections.synchronizedMap(Collections.synchronizedMap( new TreeMap<String, String>()));

我认为您的呼叫线路应更改为:

Map<String, String> key_values = Classname.function1();
于 2012-12-18T06:49:12.620 回答
1

您正在寻找一个同步的 MAP,所以我假设您正在处理一个多线程应用程序。在这种情况下,如果要使用迭代器,则必须为 MAP 同步块。

/*This reference will give error if you update the map after synchronizing values.*/
    Map<String, String> values =Collections.synchronizedMap(function1());

/*This reference will not give error if you update the map after synchronizing values  */
        Map<String, String> values = Collections.synchronizedMap(new TreeMap<String, String>());


     synchronized (values) 
                {           
                    Iterator it = values.entrySet().iterator();
                    while(it.hasNext())
                    {
                        it.next() ; 
    // You can update the map here.     
                    }
                }

更新 :

实际上,在您的情况下,考虑到您两次包装 MAP 的错误,即使使用同步块在 while 循环中对其进行修改也会产生 CM 异常,因为您将无法在正在更新的原始 MAP 对象上进行同步。

于 2012-12-18T07:10:21.390 回答
0

这就是我正在做的事情ConcurrentModificationException

TreeMap<Integer, Integer> map = new TreeMap<>();

for (Integer i : map.keySet()) {
    map.remove(i)
}

这就是我为修复异常所做的相同功能:

TreeMap<Integer, Integer> map = new TreeMap<>();

// I would not recommend this in production as it will create multiple
// copies of map
for (Integer i : new HashMap<>(integers).keySet()) {
    map.remove(i)
}
于 2020-05-30T18:12:36.597 回答