BlockingQueue - 阻止drainTo()方法

mjl*_*lee 27 java concurrency

BlockingQueue有一个名为drainTo()的方法,但它没有被阻止.我需要一个我想阻止的队列,但也能够在一个方法中检索排队的对象.

Object first = blockingQueue.take();

if ( blockingQueue.size() > 0 )
    blockingQueue.drainTo( list );
Run Code Online (Sandbox Code Playgroud)

我想上面的代码会起作用,但我正在寻找一个优雅的解决方案.

Edd*_*die 33

您是指JavaDoc中的注释:

此外,如果在操作正在进行时修改指定的集合,则此操作的行为是不确定的.

我相信这是指list你的例子中的集合:

blockingQueue.drainTo(list);
Run Code Online (Sandbox Code Playgroud)

这意味着你不能修改list你从排水的同时blockingQueue进入list.但是,阻塞队列在内部同步,以便在drainTo调用时,puts和(参见下面的注释)将阻塞.如果它没有这样做,那么它将不是真正的线程安全的.您可以查看源代码并验证drainTo关于阻塞队列本身是否是线程安全的.

或者,您是否意味着当您调用drainTo它时希望它阻塞,直到至少有一个对象被添加到队列中?在这种情况下,你别无选择:

list.add(blockingQueue.take());
blockingQueue.drainTo(list);
Run Code Online (Sandbox Code Playgroud)

阻止,直到添加了一个或多个项目,然后将整个队列排入集合list.

注意:从Java 7开始,对gets和puts使用单独的锁.现在允许在drainTo(以及许多其他采取操作)期间执行put操作.

  • `.drainTo()`的javadoc契约有点含糊不清(因为大多数自然语言契约都是),但"所有可用元素"都表示不阻塞.我已经确认这是针对Array和List阻塞队列的Android SDK实现的. (4认同)

Pet*_*ček 15

如果您碰巧使用Google Guava,那就有一种漂亮的Queues.drain()方法.

将队列排除为BlockingQueue.drainTo(Collection, int),但如果请求的numElements元素不可用,它将等待它们达到指定的超时.


Dan*_*kov 5

我发现这种模式很有用.

List<byte[]> blobs = new ArrayList<byte[]>();
if (queue.drainTo(blobs, batch) == 0) {
   blobs.add(queue.take());
}
Run Code Online (Sandbox Code Playgroud)