BlockingQueue多线程场景下add与drainTo并行调用的安全性及解决方案
多线程下
add与drainTo并行调用的安全性问题解答 你的理解不正确,原因如下:
文档里提到的“操作期间指定集合被修改,行为未定义”,指的是
drainTo的参数集合c被修改的情况,而非队列本身被add方法修改。
已知add和drainTo各自具备线程安全性,意味着队列的内部实现已经处理了并发访问的同步逻辑,并行调用时不会出现队列数据损坏、元素丢失或重复获取的问题。唯一的影响是:drainTo执行期间调用add新增的元素,不会被本次drainTo移除(因为它只处理调用时刻队列中已有的“可用元素”),这些新元素会留在队列中,等待下一次drainTo调用处理,并不会导致drainTo执行失败。
解决方案
如果你的需求是保证并发场景下的队列处理逻辑稳定,可参考以下方案:
- 使用标准并发队列实现:直接用JDK提供的
LinkedBlockingQueue、ArrayBlockingQueue这类并发安全队列,它们的add和drainTo方法已经做了完善的同步处理,并发调用时无需额外加锁,就能保证队列状态的一致性。 - 处理执行期间新增元素:如果需要一次性尽可能获取所有元素(包括
drainTo执行过程中新增的),可以循环调用drainTo直到队列为空,示例代码如下:
注意:因为并发List<E> buffer = new ArrayList<>(); while (!queue.isEmpty()) { queue.drainTo(buffer); // 处理buffer中的元素 buffer.clear(); }add的存在,这个循环可能不会立即结束,需根据业务场景控制循环的终止条件。 - 保护目标集合
c:确保drainTo的目标集合c在操作期间不被其他线程修改。如果c需要被多线程访问,建议使用CopyOnWriteArrayList这类线程安全集合,或者在操作c时加锁,避免触发文档中提到的“行为未定义”情况。
内容的提问来源于stack exchange,提问作者KunLun
相关产品推荐
相关产品推荐

