同步是否足以使BlockingQueue 的drainTo() 方法原子化?

Kam*_*ami 5 java multithreading synchronization

如果我只是做这样的事情:

synchronized(taskQueue) { //taskQueue is a BlockingQueue 
  taskQueue.drainTo(tasks); //tasks is a list
}
Run Code Online (Sandbox Code Playgroud)

我是否确信并发调用taskQueue.put()不能taskQueue.take()在同步块内执行?

换句话说,我是否使rainTo() 方法成为原子方法?

或者更一般地说,如何使线程安全操作的组合成为原子的?

例子:

if(taskQueue.size() == 1) {
   /*Do a lot of things here, but I do not want other threads
     to change the size of the queue here with take or put*/
}
//taskQueue.size() must still be equal to 1
Run Code Online (Sandbox Code Playgroud)

hag*_*wal 3

请参阅下面的BlockingQueue Java 文档摘录

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

另外,请检查示例,该示例显示 BlockingQueue 实现可以安全地与多个生产者和多个消费者一起使用。

因此,如果您不使用像这样的批量 Collection 操作,addAll, containsAll, retainAll and removeAll 那么您就是线程安全的。

您甚至不需要synchronized(taskQueue) {并且可以直接使用,taskQueue.drainTo(tasks);因为BlockingQueue 实现对于非批量收集操作(如、等)是线程安全的。puttakedrainTo

希望这可以帮助!

  • @jameslarge 我同意,除了我们知道的正常继承契约之外,接口和实现类之间没有明确的契约,但是在“BlockingQueue”的情况下,Java 文档中明确提到 - “BlockingQueue 实现是线程安全的”。和“除非在实现中另有指定,否则批量集合操作addAll、containsAll、retainAll和removeAll不一定以原子方式执行”因此,我认为不需要检查API代码并进行验证。OP 关心的是非批量收集操作。 (2认同)