java 为什么 iterator.hasNext 不适用于 BlockingQueue?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6149810/
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
Why does the iterator.hasNext not work with BlockingQueue?
提问by Varun Garde
I was trying to use the iterator methods on a BlockingQueue and discovered that hasNext() is non-blocking - i.e. it will not wait until more elements are added and will instead return false when there are no elements.
我试图在 BlockingQueue 上使用迭代器方法,发现 hasNext() 是非阻塞的 - 即它不会等到添加更多元素,而是在没有元素时返回 false。
So here are the questions :
所以这里是问题:
- Is this bad design, or wrong expectation?
- Is there a way to use the blocking methods of the BLockingQueue with its parent Collection class methods (e.g. if some method were expecting a collection, can I pass a blocking queue and hope that its processing will wait until the Queue has more elements)
- 这是糟糕的设计,还是错误的期望?
- 有没有办法将 BLockingQueue 的阻塞方法与它的父 Collection 类方法一起使用(例如,如果某个方法需要一个集合,我可以传递一个阻塞队列并希望它的处理会等到 Queue 有更多元素)
Here is a sample code block
这是一个示例代码块
public class SomeContainer{
public static void main(String[] args){
BlockingQueue bq = new LinkedBlockingQueue();
SomeContainer h = new SomeContainer();
Producer p = new Producer(bq);
Consumer c = new Consumer(bq);
p.produce();
c.consume();
}
static class Producer{
BlockingQueue q;
public Producer(BlockingQueue q) {
this.q = q;
}
void produce(){
new Thread(){
public void run() {
for(int i=0; i<10; i++){
for(int j=0;j<10; j++){
q.add(i+" - "+j);
}
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}.start();
}
}
static class Consumer{
BlockingQueue q;
public Consumer(BlockingQueue q) {
this.q = q;
}
void consume() {
new Thread() {
public void run() {
Iterator itr = q.iterator();
while (itr.hasNext())
System.out.println(itr.next());
}
}.start();
}
}
}
This Code only prints the iteration once at the most.
此代码最多只打印一次迭代。
采纳答案by Johan Sj?berg
1) Is this bad design, or wrong expectation?
1)这是糟糕的设计,还是错误的期望?
Wrong expectations since it would otherwise violate the contract of Iteratorwhich on Iterator.next()
says: Throws: NoSuchElementException - iteration has no more elements.
If next()
would block the exception would never be thrown.
错误的期望,因为否则它会违反Iterator的约定,其中Iterator.next()
说:Throws: NoSuchElementException - iteration has no more elements.
如果next()
会阻塞,则永远不会抛出异常。
2) Is there a way to use the blocking methods
2)有没有办法使用阻塞方法
Yes, for instance by extending the class and overriding the next
and hasNext
methods to use blocking routines instead. Note that hasNext
would need to always return true
in this case - which again violates the contract.
是的,例如通过扩展类并覆盖next
和hasNext
方法来使用阻塞例程。请注意,在这种情况下hasNext
需要始终返回true
- 这再次违反了合同。
回答by Sean Patrick Floyd
Just don't use iterators with Queues. Use peek()
or poll()
instead or take()
if it's a BlockingQueue
:
只是不要在队列中使用迭代器。使用peek()
或poll()
代替,或者take()
如果它是BlockingQueue
:
void consume() {
new Thread() {
@Override
public void run() {
Object value;
// actually, when using a BlockingQueue,
// take() would be better than poll()
while ((value=q.poll())!=null)
System.out.println(value);
}
}.start();
}
A Queue
is an Iterable
because it is a Collection
and hence needs to provide an iterator()
method, but that shouldn't ever be used, or you shouldn't be using a Queue in the first place.
A Queue
is anIterable
因为它是 aCollection
并且因此需要提供一种iterator()
方法,但不应该使用它,或者您首先不应该使用 Queue 。
回答by Matt
if an iterator blocked on hasNext
then the iteration would never finish unless you explicitly broke out of it, this would be quite a strange design.
如果一个迭代器被阻塞,hasNext
那么迭代永远不会完成,除非你明确地打破它,这将是一个非常奇怪的设计。
In any case the LinkedBlockingQueue
javadoc has this to say
在任何情况下,LinkedBlockingQueue
javadoc 都有这个说法
Returns an iterator over the elements in this queue in proper sequence.
The returned <tt>Iterator</tt> is a "weakly consistent" iterator that will
never throw {@link ConcurrentModificationException}, and guarantees to
traverse elements as they existed upon construction of the iterator, and
may (but is not guaranteed to) reflect any modifications subsequent to
construction.
回答by AJMansfield
I think that it may be reasonable under certain circumstances to have an Iterable
whose iterator()
will block, although having a seperate BlockingIterator
would be foolish. The reason for this is because that lests you use an enhanced for
loop, which can,in some cases, make your code cleaner. (If it would not accomplish that in your particular circumstance, do not do this at all.)
我认为在某些情况下有一个人Iterable
的iterator()
意志阻止可能是合理的,尽管有一个单独的人BlockingIterator
会很愚蠢。这样做的原因是为了避免您使用增强的for
循环,在某些情况下,它可以使您的代码更清晰。(如果它在您的特定情况下无法做到这一点,请根本不要这样做。)
for(Request request:requests) process(request);
However, the iterator is still not free from a termination condition! The iterator should terminate once the queue has been closed to new items, andruns out of elements.
然而,迭代器仍然没有终止条件!一旦队列对新项目关闭并用完元素,迭代器应该终止。
The issue still remains, though, that if the loop was already blocking on the iterator's next()
method, the only way to exit if the queue is closed is to throw an exception, which the surrounding code would need to handle correctly, If you choose to do this, make sure you explain very clearly and precisely, how your implementation works in the javadoc comments.
但是,问题仍然存在,如果循环已经阻塞在迭代器的next()
方法上,那么在队列关闭时退出的唯一方法是抛出一个异常,周围的代码需要正确处理,如果你选择这样做这一点,请确保您在 javadoc 注释中非常清楚准确地解释了您的实现是如何工作的。
回答by planetjones
The Iterator for LinkedBlockingQueue has this as its hasNext implementation:
LinkedBlockingQueue 的迭代器将其作为其 hasNext 实现:
private Node<E> current;
public boolean hasNext() {
return current != null;
}
so this will only work per call. You can wrap the method in a while(true) loop if you want to wait for elements and use the standard java Iterator idiom:
所以这只适用于每次通话。如果您想等待元素并使用标准的 java Iterator 惯用法,您可以将方法包装在 while(true) 循环中:
while (true) {
if(itr.hasNext()) {
System.out.println(itr.next());
}
}