treemap的entryset()迭代器触发fail-fast检查,核心是结构修改检测机制:迭代器通过modcount与expectedmodcount比对,若put、remove等非迭代器方法修改结构,下次next()或remove()即抛concurrentmodificationexception。

TreeMap 的 entrySet() 迭代器触发 fail-fast 检查,核心在于**结构修改检测机制**:只要在迭代过程中,有线程(包括当前线程)通过非迭代器自身方法(如 put、remove、clear 等)修改了 TreeMap 的结构(即改变了红黑树节点数量或拓扑),下一次调用迭代器的 next() 或 remove() 时就会抛出 ConcurrentModificationException。
fail-fast 触发的关键条件
TreeMap 内部维护一个 modCount 字段,记录结构修改次数;迭代器创建时会将该值快照为自己的 expectedModCount。每次调用 next() 或 remove() 前,都会检查两者是否一致:
- 不一致 → 立即抛出
ConcurrentModificationException - 一致 → 正常继续迭代
哪些操作会导致 modCount 变更(从而可能触发检查)
以下任意操作发生在迭代进行中,且未通过迭代器自身的 remove() 方法执行,都会使 modCount 自增,导致后续迭代器方法失败:
treeMap.put(key, value)treeMap.remove(key)treeMap.clear()treeMap.putAll(otherMap)-
treeMap.pollFirstEntry()或pollLastEntry()
注意:entrySet().iterator().remove() 是安全的——它会同步更新 expectedModCount,不会触发异常。
典型触发场景示例
下面代码会在第二次 it.next() 时抛出异常:
TreeMap<string integer> map = new TreeMap();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);
Iterator<map.entry integer>> it = map.entrySet().iterator();
it.next(); // 返回 a=1
map.put("d", 4); // ✅ 结构修改:modCount++
it.next(); // ❌ 抛出 ConcurrentModificationException
</map.entry></string>
如何避免意外触发
若需边遍历边修改,推荐以下方式:
- 收集待删键,遍历结束后统一
remove(key) - 使用
Iterator.remove()安全删除当前项 - 并发场景下改用
ConcurrentSkipListMap(它不 fail-fast,且线程安全) - 临时复制 keySet/entrySet(如
new ArrayList(map.entrySet()))再遍历
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











