BlockingQueue有一个名为drainTo()的方法,但它没有被阻止。我需要一个我想阻止的队列,但也能够在一个方法中检索排队的对象。
Object first = blockingQueue.take();
if ( blockingQueue.size() > 0 )
blockingQueue.drainTo( list );
我猜上面的代码会起作用,但我正在寻找一个优雅的解决方案。
答案 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.顺便说一句,它可以在锁定之前完成。