Java Iterator 不支持多线程共享使用,因其内部游标和 expectedModCount 非线程安全,会导致重复、丢失、越界或 ConcurrentModificationException;正确做法是用 BlockingQueue 作线程安全缓冲区,或为各线程分配独立子集/快照/并行流。

Java Iterator 本身不支持多线程协同读取——它不是线程安全的,多个线程共享同一个 Iterator 实例时,必然出现数据错乱、重复、丢失,甚至直接抛出 ConcurrentModificationException。这不是使用姿势问题,而是设计使然:Iterator 是单线程遍历工具,它的状态(如游标位置、expectedModCount)只对一个消费者有效。
为什么不能让多个线程共用一个 Iterator
ArrayList 的迭代器内部维护 expectedModCount 和当前索引 cursor。一旦两个线程同时调用 next():
- 它们可能都读到同一个索引位置(比如都读了第5个元素),造成重复消费;
- 其中一个线程推进了 cursor,另一个线程却没感知,导致跳过或越界;
- 若期间有线程修改了集合(如 add/remove),
checkForComodification()立即触发异常。
正确做法:用线程安全的“缓冲区”替代共享 Iterator
把原始数据源(如 List)看作生产源头,用一个线程安全的队列作为中转,由生产者线程一次性加载并入队,再由多个消费者线程从队列中取数据。这才是多线程消费的标准解法。
- 推荐使用
BlockingQueue实现,例如ArrayBlockingQueue或LinkedBlockingQueue; - 单个生产者线程调用
iterator()遍历原始集合,逐个put()到队列; - 多个消费者线程调用
take()(阻塞获取)或poll(timeout)(超时获取),天然线程安全且无竞争; - 无需手动同步、wait/notify,队列自身保证可见性与原子性。
如果必须用集合 + 多消费者,该怎么做
不建议复用 Iterator,但可以为每个消费者分配独立的数据视图:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 将原始集合切片(如按索引分段),每个线程持有一份子 List,各自创建自己的 Iterator;
- 使用
CopyOnWriteArrayList:适合读多写少场景,迭代器基于快照,不会抛 CME,但无法解决“多个线程推进同一份数据”的逻辑冲突; - 改用
Spliterator+ 并行流(collection.parallelStream()):底层自动分区、线程隔离,适合纯计算型消费,不适用于需要状态协作的场景。
避坑提醒
以下操作在多线程下一律无效或危险:
- 对
Collections.synchronizedList(list).iterator()的结果多线程调用 —— 同步的是 list 方法,不是 iterator 状态; - 用
synchronized(iterator)包裹next()—— 迭代器内部字段(如 cursor)仍非 volatile,无法保证可见性; - 用 Vector 或手动加锁模拟“安全迭代” —— 极易死锁,且违背迭代器抽象本意。
多线程消费的本质是解耦“数据供给”和“任务执行”,不是强行让 Iterator 并发化。用 BlockingQueue 做缓冲,才是清晰、可靠、可扩展的选择。

















