我试图在BlockingQueue上使用迭代器方法,并发现hasNext()是非阻塞的 - 即它不会等到添加更多元素,而是在没有元素时返回false。
以下是问题:
以下是示例代码块
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();
}
}
}
此代码仅打印最多一次迭代。
答案 0 :(得分:10)
只是不要将迭代器与队列一起使用。如果是BlockingQueue
,请使用peek()
或poll()
或take()
:
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();
}
Queue
是Iterable
,因为它是Collection
,因此需要提供iterator()
方法,但不应该使用,或者你不应该首先要使用队列。
答案 1 :(得分:4)
1)这是糟糕的设计还是错误的期望?
错误的期望,否则会违反Iterator.next()
Throws: NoSuchElementException - iteration has no more elements.
所说的Iterator合同:next()
如果next
阻止,则永远不会抛出异常。
2)有没有办法使用阻止方法
是的,例如通过扩展类并重写hasNext
和hasNext
方法来改为使用阻塞例程。请注意,true
在这种情况下需要始终返回{{1}} - 这又违反了合同。
答案 2 :(得分:3)
如果迭代器在hasNext
上被阻塞,那么迭代将永远不会完成,除非你明确地突破它,这将是一个非常奇怪的设计。
在任何情况下,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.
答案 3 :(得分:0)
我认为在某些情况下,Iterable
iterator()
阻止BlockingIterator
可能是合理的,尽管单独for
会是愚蠢的。这样做的原因是因为这会让您使用增强的for(Request request:requests) process(request);
循环,在某些情况下,这可以使您的代码更清晰。 (如果在特定情况下无法实现,请不要这样做。)
next()
然而,迭代器仍然没有终止条件!一旦队列关闭到新项目,和用完了元素,迭代器应该终止。
但问题仍然存在,如果循环已经在迭代器的{{1}}方法上阻塞,那么在队列关闭时退出的唯一方法是抛出一个异常,周围的代码需要这个异常正确处理,如果你选择这样做,请确保你非常清楚,准确地解释你的实现如何在javadoc注释中工作。
答案 4 :(得分:-1)
LinkedBlockingQueue的迭代器将其作为hasNext实现:
private Node<E> current;
public boolean hasNext() {
return current != null;
}
所以这只适用于每次通话。如果要等待元素并使用标准的java Iterator惯用语,可以将方法包装在while(true)循环中:
while (true) {
if(itr.hasNext()) {
System.out.println(itr.next());
}
}