iterator非线程安全,多线程共享必出错;应单线程独占使用、避免暴露或跨线程传递;需并发时改用copyonwritearraylist等线程安全集合加锁遍历,或采用快照、parallelstream等更安全方案。

Iterator 本身不是线程安全的,多线程环境下直接共享使用同一个 Iterator 实例必然导致冲突或异常。
它本质是单线程游标模型,设计上不支持并发访问。要避免冲突,关键不是“让 Iterator 变线程安全”,而是规避共享、隔离访问、改用合适工具。
别让多个线程共用一个 Iterator
Iterator 是“一次性”“有状态”的遍历器,内部维护 `cursor` 和 `expectedModCount`。一旦被多个线程同时调用 `next()` 或 `remove()`,极易触发 `ConcurrentModificationException`,甚至读到脏数据。- 单个 Iterator 实例只应在单一线程内创建并全程使用
- 绝对不要将
iterator()返回的对象暴露给其他线程 - 不要把 Iterator 存在静态变量、共享缓存或跨线程传递
用线程安全的集合 + 同步控制遍历
如果必须边遍历边修改(比如筛选删除),且集合本身会被多线程写入,推荐组合方案:- 使用线程安全集合:如
CopyOnWriteArrayList、ConcurrentHashMap(注意:它们的iterator()仍是弱一致性,但不抛 CME) - 对遍历逻辑加锁:确保“获取 iterator → 遍历 → 修改”整个过程原子化
List<string> list = new CopyOnWriteArrayList();
synchronized (list) {
Iterator<string> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if (s.startsWith("temp")) it.remove(); // 安全
}
}</string></string>
优先用不可变快照或并行流替代手动迭代
避免在多线程中手动管理 Iterator,转而采用更健壮的抽象:- 遍历前生成快照:
new ArrayList(originalList),再在副本上用普通 Iterator —— 适合读多写少、数据量不大的场景 - 用
parallelStream()处理只读遍历:底层基于 Spliterator,天然支持分片与并行,无需手动同步 - 写操作走专用线程或队列:如用
BlockingQueue收集待处理项,由单个消费者线程统一遍历处理
警惕 for-each 循环的隐式陷阱
`for (String s : list)` 看似简洁,但底层仍调用 `list.iterator()`。若循环体中调用 `list.remove()`(非 `it.remove()`),就会触发 fail-fast:- ✅ 正确:用显式 Iterator 并调用其
remove()方法(仅限单线程) - ❌ 错误:在 for-each 中直接调
list.remove(s),无论是否多线程都会出错 - ⚠️ 危险:在多线程里用 for-each 遍历非线程安全集合,即使不删元素,也可能因结构变更而失败
不复杂但容易忽略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











