HashMap底层使用的是数组+链表/红黑树的方式实现的
在并发场景下同时进行遍历+删除,会出现ConcurrentModificationException
异常,这是因为HashMap的迭代器是快速失败的(fail-fast),当检测到结构性的改变(比如增加或删除元素)时会立即抛出异常
遍历HashMap时,如果删除元素,会触发这个异常,这是因为迭代器在遍历过程中维护了一个预期修改次数,而HashMap的修改会更新这个预期修改次数,当这个预期修改次数和期望值不一样时,会抛出 ConcurrentModificationException
异常
解决:
-
使用Iterator的remove方法
Iterator<Map.Entry<KeyType, ValueType>> iterator = map.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<KeyType, ValueType> entry = iterator.next(); if (someCondition(entry)) { iterator.remove(); // 使用迭代器的remove方法 } }
-
收集要删除的键,遍历结束之后再删除
List<KeyType> keysToRemove = new ArrayList<>(); for (Map.Entry<KeyType, ValueType> entry : map.entrySet()) { if (someCondition(entry)) { keysToRemove.add(entry.getKey()); } } for (KeyType key : keysToRemove) { map.remove(key); }
-
使用并发集合:使用线程安全的ConcurrentHashMap,可以运行在并发环境中同时进行遍历和删除
-
复制原集合:可以先复制一个HashMap到新集合中,然后在新集合上进行删除操作,最后转会原集合
一般推荐使用ConcurrentHashMap来避免这类问题