BlockingQueue – 阻止drainTo()方法

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

Object first = blockingQueue.take(); if ( blockingQueue.size() > 0 ) blockingQueue.drainTo( list ); 

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

你是指JavaDoc中的注释:

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

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

 blockingQueue.drainTo(list); 

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

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

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

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

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

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

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

我发现这种模式很有用。

 List blobs = new ArrayList(); if (queue.drainTo(blobs, batch) == 0) { blobs.add(queue.take()); } 

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

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

源代码:

  596: public int drainTo(Collection 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.顺便说一句,它可以在锁定之前完成。