自定义HashMap中增强for循环抛ConcurrentModificationException问题咨询
自定义HashMap遍历与修改的ConcurrentModificationException问题
在实现自定义HashMap时发现:使用传统索引for循环遍历并修改LinkedList桶时能正常运行,但用增强for循环(底层依赖Iterator)或直接使用Iterator遍历修改时,会抛出java.util.ConcurrentModificationException异常。即便将增强for循环放入同步块,问题依然存在。
以下是可正常运行的代码(remove方法使用传统for循环):
class MyHashMap { public final int MAX_VALUE = 1009; // 选用大质数作为桶数量 LinkedList<Node> buckets[]; public MyHashMap() { buckets = new LinkedList[MAX_VALUE]; for (int i = 0; i < buckets.length; i++) buckets[i] = new LinkedList<Node>(); } public void put(int key, int value) { int index = key % MAX_VALUE; LinkedList<Node> list = buckets[index]; if (get(key) != -1) remove(key); // 存在则先删除再更新 Node entry = new Node(key, value); list.add(entry); } public int get(int key) { int index = key % MAX_VALUE; List<Node> list = buckets[index]; if(list == null) return -1; for(Node n : list){ if(n.key == key) return n.val; } return -1; } public void remove(int key) { int index = key % MAX_VALUE; LinkedList<Node> list = buckets[index]; if(list == null) return; // synchronized(this){ for(int i = 0; i < list.size(); i++){ Node n = list.get(i); if(n.key == key){ list.remove(n); break; } } // } } } class Node{ public int key; public int val; public Node(int key, int val){ this.key = key; this.val = val; } } /** * Your MyHashMap object will be instantiated and called as such: * MyHashMap obj = new MyHashMap(); * obj.put(key,value); * int param_2 = obj.get(key); * obj.remove(key); */
问题解答
1. 为何传统循环可行,而增强for循环和迭代器却不行?
Java的LinkedList属于**快速失败(fail-fast)**集合,内部维护了一个修改计数器modCount。
- 传统索引for循环:直接通过索引访问元素,调用
list.remove(n)会增加集合的modCount,但因为没有迭代器做一致性校验,所以不会触发异常(不过这种方式存在索引偏移风险,这里因找到元素后直接break才未暴露问题)。 - 增强for/Iterator:遍历过程中,迭代器会记录当前的
modCount,每次迭代都会检查该值是否与集合当前的modCount一致。调用list.remove(n)会修改集合的modCount,迭代器持有的旧值与新值不一致,下一次校验时就会抛出ConcurrentModificationException。
2. java.util.ConcurrentModificationException异常具体表示什么?
这个异常用于检测集合的并发修改问题,当集合在迭代过程中被非迭代器自身的方法修改时,就会抛出该异常。它的核心作用是提前发现修改不一致的bug,避免出现遍历结果异常或其他不可预期的行为。注意:它不仅会在多线程并发场景下触发,单线程中迭代时直接修改集合也会触发。
3. 为何在同步块中使用增强for循环(确保单线程锁定迭代)无法解决该异常?
同步块仅能保证同一时间只有一个线程访问代码块,但问题根源并非多线程并发,而是单线程中用Iterator遍历的同时,直接调用了集合的remove()方法修改集合。即便加了同步块,迭代器的modCount校验机制依然会触发:迭代器记录的modCount与集合实际的modCount因调用list.remove(n)产生差异,因此仍会抛出异常。只有使用迭代器自身的remove()方法,才会同步更新迭代器内部的modCount,避免触发异常。
内容的提问来源于stack exchange,提问作者alamshahbaz16497
相关产品推荐
相关产品推荐

