BlockingQueue - 阻止drainTo()方法

时间:2009-05-06 21:22:24

标签: java concurrency

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

Object first = blockingQueue.take();

if ( blockingQueue.size() > 0 )
    blockingQueue.drainTo( list );

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

5 个答案:

答案 0 :(得分:32)

您是指JavaDoc中的评论:

  

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

我认为这是指您示例中的集合list

blockingQueue.drainTo(list);

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

或者,您是否意味着在调用drainTo之前要将其阻止,直到至少有一个对象添加到队列中?在这种情况下,你别无选择:

list.add(blockingQueue.take());
blockingQueue.drainTo(list);

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

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

答案 1 :(得分:13)

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

  

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

答案 2 :(得分:5)

我发现这种模式很有用。

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

答案 3 :(得分:0)

有了API,我认为你不会变得更优雅。除了你可以删除尺寸测试。

如果你想原子地检索一个连续的元素序列,即使另一个删除操作重合,我也不相信即使drainTo也能保证这一点。

答案 4 :(得分:-1)

源代码:

 596:     public int drainTo(Collection<? super E> c) {
              //arg. check
 603:         lock.lock();
 604:         try {
 608:             for (n = 0 ; n != count ; n++) {
 609:                 c.add(items[n]);
 613:             }
 614:             if (n > 0) {
 618:                 notFull.signalAll();
 619:             }
 620:             return n;
 621:         } finally {
 622:             lock.unlock();
 623:         }
 624:     }

ArrayBlockingQueue急于返回0.顺便说一句,它可以在锁定之前完成。