LinkedBlockingQueue 的 iterator 是 fail-fast 的,不线程安全,并发删改时会抛 ConcurrentModificationException;它不参与 putLock/takeLock 同步,仅通过 modCount 校验结构性修改,设计上不保证遍历过程的并发安全。

LinkedBlockingQueue 的 iterator 不是线程安全的,**在并发删改场景下直接使用会抛出 ConcurrentModificationException**。
迭代器本身不保证并发安全
LinkedBlockingQueue 实现了 Iterable 接口,支持 for-each 遍历,但它的迭代器属于典型的 fail-fast(快速失败)机制:
- 内部维护一个 modCount 计数器,记录队列结构修改次数;
- 迭代器创建时会记录初始 modCount 值(expectedModCount);
- 每次调用 next() 时都会校验 modCount 是否被其他线程修改过;
- 一旦发现不一致,立即抛出 ConcurrentModificationException。
注意:这个检查只针对“结构性修改”——比如 put/take/remove/clear 等改变队列节点数量的操作。单纯读取(如 peek、size)不会触发异常,但也不能规避竞态风险。
不能靠 iterator.remove() 解决并发问题
虽然 LinkedBlockingQueue 的迭代器也提供了 remove() 方法,但它仅适用于单线程遍历中“安全删除当前元素”,不适用于多线程环境下的协作修改:
立即学习“Java免费学习笔记(深入)”;
- iterator.remove() 只能由持有该迭代器的线程调用,且必须紧跟在 next() 之后;
- 若另一线程同时执行 put 或 take,仍会触发 modCount 不匹配,导致异常;
- 它不加锁,也不参与 LinkedBlockingQueue 内部的 takeLock/putLock 同步体系。
真正需要并发遍历时的替代方案
如果业务逻辑确实要求“边遍历边由多个线程协同修改”,不应依赖 iterator,而应选择更合适的手段:
- 分批消费 + 显式同步:用 take()/poll() 拿出一批元素处理,避免长时间持有一个迭代器;
- 转为不可变快照:调用 toArray() 获取当前时刻的 Object[] 数组副本,在副本上遍历和筛选(无并发风险,但不反映实时状态);
- 换用 CopyOnWrite 数据结构:如需高频读+低频写+安全遍历,考虑 CopyOnWriteArrayList,但它不是阻塞队列,无法替代 LinkedBlockingQueue 的生产者-消费者语义;
- 避免遍历,改用事件驱动:多数真实场景中,并不需要“扫描全队列”,而是通过 take() 阻塞获取新任务,这才是 LinkedBlockingQueue 的设计本意。
为什么它不像队列操作那样自带锁
LinkedBlockingQueue 对 put/take 类操作使用两把独立锁(putLock 和 takeLock),实现读写分离,提升吞吐量。但 iterator 是只读视图,Java 设计上未将其纳入锁保护范围:
- 迭代器不修改队列结构,所以不参与 putLock/takeLock 的协作;
- 若强制给 iterator 加锁,会严重拖慢遍历性能,违背高并发队列的设计目标;
- fail-fast 的定位是“及时发现问题”,而非“防止问题发生”。
换句话说:它不提供并发安全的遍历能力,这是明确的设计取舍,不是缺陷。


















