java - LinkedHashMap 的 ConcurrentModificationException

标签 java concurrentmodification linkedhashmap

当我遍历下面代码中的 LinkedHashMap 结构时,不确定是什么触发了 java.util.ConcurrentModificationException。使用 Map.Entry 方法效果很好。没有从以前的帖子中得到关于触发此问题的良好解释。

如有任何帮助,我们将不胜感激。

import java.util.LinkedHashMap;
import java.util.Map;

public class LRU {

    // private Map<String,Integer> m = new HashMap<String,Integer>();
    // private SortedMap<String,Integer> lru_cache = Collections.synchronizedSortedMap(new TreeMap<String, Integer>());

    private static final int MAX_SIZE = 3;

    private LinkedHashMap<String,Integer> lru_cache = new LinkedHashMap<String,Integer>(MAX_SIZE, 0.1F, true){
        @Override
        protected boolean removeEldestEntry(Map.Entry eldest) {
            return(lru_cache.size() > MAX_SIZE);
         }
    };    

    public Integer get1(String s){
        return lru_cache.get(s);        
    }

    public void displayMap(){
        /**
         * Exception in thread "main" java.util.ConcurrentModificationException
            at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(LinkedHashMap.java:373)
            at java.util.LinkedHashMap$KeyIterator.next(LinkedHashMap.java:384)
            at LRU.displayMap(LRU.java:23)
            at LRU.main(LRU.java:47)
         */
        *for(String key : lru_cache.keySet()){
            System.out.println(lru_cache.get(key));
        }*

// This parser works fine        
//        for(Map.Entry<String, Integer> kv : lru_cache.entrySet()){
//            System.out.println(kv.getKey() + ":" + kv.getValue());
//        }
    }

    public void set(String s, Integer val){
        if(lru_cache.containsKey(s)){            
            lru_cache.put(s, get1(s) + val);
        }
        else{
            lru_cache.put(s, val);
        }
    }

    public static void main(String[] args) {

        LRU lru = new LRU();
        lru.set("Di", 1);
        lru.set("Da", 1);
        lru.set("Daa", 1);
        lru.set("Di", 1);        
        lru.set("Di", 1);
        lru.set("Daa", 2);
        lru.set("Doo", 2);
        lru.set("Doo", 1);        
        lru.set("Sa", 2);
        lru.set("Na", 1);
        lru.set("Di", 1);
        lru.set("Daa", 1);

        lru.displayMap();

    }

}

最佳答案

阅读Javadoc for LinkedHashMap :

A structural modification is any operation that adds or deletes one or more mappings or, in the case of access-ordered linked hash maps, affects iteration order. In insertion-ordered linked hash maps, merely changing the value associated with a key that is already contained in the map is not a structural modification. In access-ordered linked hash maps, merely querying the map with get is a structural modification.

由于您传入 trueLinkedHashMap构造函数,它在访问顺序中,当你试图 get从它的某些东西,你正在结构上修改它。

另请注意,当您使用增强的 for 时语法,您实际上是在使用迭代器。来自 JLS §14.14.2 的简化报价:

The enhanced for statement has the form:

EnhancedForStatement:

for ( TargetType Identifier : Expression ) Statement

[...]

If the type of Expression is a subtype of Iterable<X> for some type argument X, then let I be the type java.util.Iterator<X>; otherwise, let I be the raw type java.util.Iterator.

The enhanced for statement is equivalent to a basic for statement of the form:

for (I #i = Expression.iterator(); #i.hasNext(); ) {
     TargetType Identifier =
         (TargetType) #i.next();
     Statement
}

#i is an automatically generated identifier that is distinct from any other identifiers (automatically generated or otherwise) that are in scope (§6.3) at the point where the enhanced for statement occurs.

此外,在 LinkedHashMap 的 Javadoc 中:

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.

因此,当您调用 get 时在 map 上,您正在对其进行结构修改,导致增强型 for 中的迭代器抛出异常。我认为你打算这样做,这样可以避免调用 get :

for (Integer i : lru_cache.values()) {
    System.out.println(i);
}

关于java - LinkedHashMap 的 ConcurrentModificationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16180568/

相关文章:

java - 如何在运行时更改 slf4j 级别?

java - 如何在java中创建网页的哈希值?

java - 在迭代时修改列表

java - 正确地从树中删除节点

java - 排序 LinkedHashMap

java - 带有 JAX-RX 的 REST API 从 jsp 页面中的表单发送和接收已解析的 JSON

java - 是否有 "heavy class"这样的东西?它的正确定义是什么?

java - 为什么 Java Set 上的 ConcurrentModificationException 会转储有关 Map 迭代器的堆栈跟踪?

java - 使用 LinkedHashMap 的字符串中的第一个唯一字符

java - linkedhashmap 的重复项