阻塞队列排水管To()方法的线程安全

2022-09-02 21:25:37

BlockingQueue的文档说批量操作不是线程安全的,尽管它没有明确提到referTo()方法。

阻塞队列实现是线程安全的。所有排队方法都使用内部锁或其他形式的并发控制以原子方式实现其效果。但是,除非在实现中另有指定,否则大容量收集操作 addAll、containAll、retainAll 和 removeAll 不一定是以原子方式执行的。因此,例如,addAll(c) 在 c 中仅添加一些元素后可能会失败(引发异常)。

drainTo() 方法的文档指定不能以线程安全的方式修改 BlockingQueue 的元素所消耗到的集合。但是,它没有提到任何关于 drainTo() 操作是线程安全的。

从此队列中删除所有可用元素,并将它们添加到给定的集合中。此操作可能比重复轮询此队列更有效。尝试将元素添加到集合 c 时遇到的失败可能会导致在引发关联的异常时,元素不在集合中,或者两者都在集合中。尝试将队列排出到自身会导致非法参数异常。此外,如果在操作过程中修改了指定的集合,则此操作的行为未定义。

那么,drainTo() 方法线程安全吗?换句话说,如果一个线程在阻塞队列上调用了 drainTo() 方法,而另一个线程在同一队列上调用 add() 或 put(),那么在两个操作结束时,队列的状态是否一致?


答案 1

我认为你混淆了术语“线程安全”和“原子”。它们的意思不是一回事。方法可以是线程安全的,但不是原子的,也可以是原子的(对于单个线程),而不是线程安全的。

线程安全是一个橡皮术语,如果不带圆形,就很难定义。根据Goetz的说法,一个好的工作模型是,如果一个方法在多线程上下文中使用时是“正确的”,那么它是线程安全的,因为它在单线程上下文中运行。橡胶性在于,正确性是主观的,除非你有一个正式的规范来衡量。

相比之下,原子很容易定义。它只是意味着操作要么完全发生,要么根本不发生。

所以你的问题的答案是线程安全的,但不是原子的。它不是原子的,因为它可能会在耗尽中途引发异常。但是,无论其他线程是否同时对队列执行操作,队列仍将处于一致状态。drainTo()


(在上面的讨论中隐含着接口的特定实现正确实现接口。如果没有,则所有赌注都被取消。BlockingQueue


答案 2

drainTo()是线程安全的,因为队列上同时发生的任何操作都不会改变结果,也不会破坏队列的状态。否则,该方法将毫无意义。

如果目标集合(将结果添加到的目标集合)执行“聪明”操作,则可能会遇到问题。但是,由于您通常会将队列排到只有单个线程有权访问的集合中,因此这更像是一个理论问题。


推荐