多线程遍历集合冲突源于fail-fast机制与未同步的结构性修改;推荐快照遍历(如toarray)、copyonwritearraylist(读多写少)、concurrenthashmap(键值查找场景),避免混用锁和迭代器。

多线程环境下遍历集合时出现冲突,核心问题是 Iterator 的 fail-fast 机制 和 结构性修改未同步。不是“不能遍历”,而是“边遍历边改”或“不同步的遍历+修改”会触发 ConcurrentModificationException,甚至引发逻辑错误或死锁。关键不在 Iterator 本身,而在如何协调读与写。
用快照方式遍历(推荐首选)
不加锁、无阻塞、零死锁风险,适合绝大多数读多写少场景。
- 调用
list.toArray()或new ArrayList(list)先复制当前状态,再遍历副本 - 原集合可被其他线程自由增删,互不影响
- 内存开销可控:若只遍历并读取字段,可只复制关键数据(如 ID 列表),而非整个对象
换用 CopyOnWriteArrayList
专为高并发读设计,迭代器天然基于快照,完全规避异常。
- 迭代器创建后,后续
add/remove不影响当前遍历结果 - 写操作性能差(每次复制整个数组),严禁用于写频繁场景(如每秒上百次修改)
- 迭代器不支持
remove(),调用会抛UnsupportedOperationException
加锁控制(需谨慎)
仅在必须强一致性且写操作极少时考虑,否则易成性能瓶颈或死锁源头。
- 所有访问(包括
iterator()、next()、add()、remove())必须使用同一把锁,推荐synchronized(list) - 遍历体内避免耗时操作;如需处理单个元素较久,应先取出数据,再释放锁
- 切勿混合使用显式锁(如
ReentrantLock)和synchronizedList的迭代器——这极易因锁顺序不一致导致死锁
考虑替代结构(按场景选)
如果遍历常伴随键值查找,或本身是映射关系,ConcurrentHashMap 往往比 List 更合适。
- 其
keySet().iterator()是弱一致性迭代器:不抛异常,允许并发修改,也不保证瞬时全量视图 - 比
CopyOnWriteArrayList写性能好得多,扩容和并发写支持更成熟 - 若业务本质是“按 ID 查找 + 批量通知”,用
ConcurrentHashMap<id value></id>比维护一个 List 更自然、更安全
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











