Java BlockingQueue - 阻塞的 drainTo() 方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/831834/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 19:59:03  来源:igfitidea点击:

BlockingQueue - blocked drainTo() methods

javaconcurrency

提问by mjlee

BlockingQueue has the method called drainTo() but it is not blocked. I need a queue that I want to block but also able to retrieve queued objects in a single method.

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

Object first = blockingQueue.take();

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

I guess the above code will work but I'm looking for an elegant solution.

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

采纳答案by Eddie

Are you referring to the comment in the JavaDoc:

您指的是JavaDoc 中的评论:

Further, the behavior of this operation is undefined if the specified collection is modified while the operation is in progress.

此外,如果在操作进行时修改了指定的集合,则此操作的行为未定义。

I believe that this refers to the collection listin your example:

我相信这指的list是您示例中的集合:

blockingQueue.drainTo(list);

meaning that you cannot modify listat the same time you are draining from blockingQueueinto list. However, the blocking queue internally synchronizes so that when drainTois called, puts and(see note below) gets will block. If it did not do this, then it would not be truly Thread-safe. You can look at the source code and verify that drainTois Thread-safe regarding the blocking queue itself.

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

Alternately, do you mean that when you call drainTothat you want it to block until at least one object has been added to the queue? In that case, you have little choice other than:

或者,你的意思是当你调用drainTo它时你希望它阻塞直到至少有一个对象被添加到队列中?在这种情况下,除了:

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

to block until one or more items have been added, and then drain the entire queue into the collection list.

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

Note: As of Java 7, a separate lock is used for gets and puts. Put operations are now permitted during a drainTo (and a number of other take operations).

注意:从 Java 7 开始,单独的锁用于获取和放置。现在允许在drainTo(以及许多其他take 操作)期间执行put 操作。

回答by Tom Hawtin - tackline

With the API available, I don't think you are going to get much more elegant. Other than you can remove the size test.

有了可用的 API,我认为您不会变得更优雅。除了您可以删除大小测试。

If you are wanting to atomically retrieve a contiguous sequence of elements even if another removal operation coincides, I don't believe even drainToguarantees that.

如果即使另一个删除操作同时发生,您也想以原子方式检索连续的元素序列,我认为甚至不能drainTo保证。

回答by Val

Source code:

源代码:

 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 is eager to return 0. BTW, it could do it before taking the lock.

ArrayBlockingQueue 渴望返回 0。顺便说一句,它可以在获取锁之前做到这一点。

回答by Daneel S. Yaitskov

I found this pattern useful.

我发现这个模式很有用。

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

回答by Petr Jane?ek

If you happen to use Google Guava, there's a nifty Queues.drain()method.

如果你碰巧使用谷歌番石榴,有一个很好的Queues.drain()方法。

Drains the queue as BlockingQueue.drainTo(Collection, int), but if the requested numElementselements are not available, it will wait for them up to the specified timeout.

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