Java迭代器不可多线程共享,因其内部游标状态未同步且无安全读写API;应改用独立迭代器、预分片、阻塞队列或原子索引等线程安全方案。

Java 迭代器本身不适合在多线程间共享或传递游标状态。它的游标(cursor)是内部可变状态,绑定在单个迭代器实例上,一旦被多个线程同时调用 next() 或 hasNext(),就会出现状态竞争——比如重复取值、跳过元素、抛 ConcurrentModificationException,甚至数据不一致。
为什么不能直接传递游标状态
迭代器不是“游标值”的容器,而是“游标行为”的封装体:
- 游标位置(如
cursor字段)是私有且无同步保护的; - 每次
next()都会修改它,并依赖当前集合的modCount做一致性校验; - 没有公开 API 读取或设置游标位置,
Iterator接口也不支持“保存/恢复游标”语义。
替代方案:用线程安全的方式实现协作遍历
若需多线程协同处理一个数据源,应放弃“共享同一个迭代器”,转而采用以下更可靠的方式:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
-
每个线程持有一个独立迭代器:调用
collection.iterator()多次,得到彼此隔离的实例。适用于只读遍历,且集合不被其他线程修改; -
预分片 + 独立子集遍历:将原始集合切分为若干不重叠的子列表(如按索引范围),各线程处理自己的分片。适合
ArrayList等支持随机访问的结构; -
使用线程安全队列中转:由一个生产者线程通过迭代器逐个
offer元素到BlockingQueue,多个消费者线程take()处理——游标推进由单一线程控制,天然规避并发问题; -
基于位置的显式索引协作:若底层是数组或列表,可让线程通过
AtomicInteger争抢下一个有效索引(如index.getAndIncrement()),再从集合中直接get(i),绕开迭代器机制。
特别注意:不要尝试“序列化游标”或“复制迭代器”
迭代器通常不实现 Serializable,且其内部状态(如 expectedModCount、cursor、引用的集合快照)无法安全重建。手动保存字段再构造新实例,大概率导致 ConcurrentModificationException 或越界异常。Java 的迭代器设计本就面向单线程、短生命周期使用场景。
立即学习“Java免费学习笔记(深入)”;
真正需要跨线程传递遍历进度时,应把“游标”抽象为外部可控的、线程安全的偏移量或令牌(如 long offset、String cursorId),由业务逻辑层统一管理,而不是依赖 Iterator 实例本身。

















