多线程调用LinkedList.poll()是否需同步或使用并发List?
关于多线程调用LinkedList.poll()的线程安全问题
嘿,这个问题抓得很准!咱们直接说重点:
核心结论
你必须做线程安全控制,要么手动同步LinkedList的poll()调用,要么直接用Java并发包提供的线程安全队列实现——因为原生的LinkedList根本不是线程安全的,多线程同时调用poll()会出问题。
为什么原生LinkedList不行?
LinkedList的poll()方法内部要做几件事:检查头节点是否为空,不为空的话就修改头节点引用、断开旧头节点的链接。这些操作没有任何同步保护,多线程同时执行时会触发竞态条件:
- 可能出现两个线程同时拿到同一个头节点,导致重复获取元素;
- 更严重的可能破坏链表结构,比如节点引用丢失、甚至引发死循环,后续操作直接报错。
完全不符合你“无重复元素”的要求。
两种可行解决方案
1. 手动给LinkedList加同步控制
如果一定要用现有的LinkedList实例,那每次调用poll()都必须在同步块里执行,确保同一时间只有一个线程能操作链表:
// 用synchronized块包裹调用 synchronized(yourLinkedList) { return yourLinkedList.poll(); }
或者用ReentrantLock来实现同步,灵活度更高,适合复杂场景。不过这种方式本质上是把并发操作变成了串行,高并发下性能会打折扣。
2. 改用并发队列实现(更推荐)
Java并发包已经给我们做好了现成的解决方案,直接用ConcurrentLinkedQueue就完美适配你的需求:
- 它的
poll()方法本身就是线程安全的,基于CAS操作实现无锁并发,性能比同步LinkedList好很多; - 空队列时
poll()返回null,和LinkedList的poll()行为完全一致,不需要改太多代码。
另外如果需要阻塞等待的场景,LinkedBlockingQueue也是选项,但你的场景用ConcurrentLinkedQueue更合适。
测试建议
你写测试的时候,可以这么做:
- 初始化一个装满元素的队列;
- 启动N个线程,每个线程循环调用
poll()直到返回null,把自己拿到的元素存起来; - 所有线程结束后,把所有线程的结果合并,检查是否有重复元素,同时看总元素数是否和初始元素数一致;
- 额外观察是否有
ConcurrentModificationException或者其他异常抛出,验证线程安全的有效性。
内容的提问来源于stack exchange,提问作者Sikorski
相关产品推荐
相关产品推荐

