如果我只是做这样的事情:
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
答案 0 :(得分:3)
以LinkedBlockingQueue为例,它有一个' takeLock'和' putLock'这是它的成员变量。
所以客户端同步在这里没有帮助,因为其他人采取了这样的措施。即使此锁来自队列本身,此锁也不会保护操作。
drainTo()方法由“takeLock'”保护,对于任何其他'采取'操作它的线程安全。但对于' put'操作,它们由“putLock”保护,因此不会受到影响。
所以我认为这里不需要任何东西!
答案 1 :(得分:3)
BlockingQueue实现是线程安全的。所有排队方法都使用内部锁或其他形式以原子方式实现其效果 并发控制。但是,批量收集操作 addAll,containsAll,retainAll和removeAll不一定 除非在实现中另有说明,否则以原子方式执 因此,例如,addAll(c)可能会失败(抛出一个 例外情况)只添加了c。
中的一些元素
另外,请查看示例,该示例显示BlockingQueue实现可以安全地与多个生产者和多个消费者一起使用。
因此,如果您没有使用像addAll, containsAll, retainAll and removeAll
那样的批量收集操作,那么您就是线程安全的。
您甚至不需要synchronized(taskQueue) {
并且可以直接使用taskQueue.drainTo(tasks);
,因为 BlockingQueue实现是线程安全的,适用于非put
等非批量收集操作,take
,drainTo
等。
希望这有帮助!