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

时间:2015-06-21 12:12:32

标签: java multithreading synchronization

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

synchronized(taskQueue) { //taskQueue is a BlockingQueue 
  taskQueue.drainTo(tasks); //tasks is a list
}

我确定无法在同步块内执行对taskQueue.put()taskQueue.take()的并发调用吗?

换句话说,我是否将drainTo()方法设为原子?

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

示例:

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

2 个答案:

答案 0 :(得分:3)

以LinkedBlockingQueue为例,它有一个' takeLock'和' putLock'这是它的成员变量。

所以客户端同步在这里没有帮助,因为其他人采取了这样的措施。即使此锁来自队列本身,此锁也不会保护操作。

drainTo()方法由“takeLock'”保护,对于任何其他'采取'操作它的线程安全。但对于' put'操作,它们由“putLock”保护,因此不会受到影响。

所以我认为这里不需要任何东西!

答案 1 :(得分:3)

见以下Java docs of BlockingQueue

的摘录
  

BlockingQueue实现是线程安全的。所有排队方法都使用内部锁或其他形式以原子方式实现其效果   并发控制。但是,批量收集操作   addAll,containsAll,retainAll和removeAll不一定   除非在实现中另有说明,否则以原子方式执   因此,例如,addAll(c)可能会失败(抛出一个   例外情况)只添加了c。

中的一些元素

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

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

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

希望这有帮助!