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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 14:33:28  来源:igfitidea点击:

Why does the iterator.hasNext not work with BlockingQueue?

javamultithreadingcollectionsjava.util.concurrent

提问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 :

所以这里是问题:

  1. Is this bad design, or wrong expectation?
  2. 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)
  1. 这是糟糕的设计,还是错误的期望?
  2. 有没有办法将 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 nextand hasNextmethods to use blocking routines instead. Note that hasNextwould need to always return truein this case - which again violates the contract.

是的,例如通过扩展类并覆盖nexthasNext方法来使用阻塞例程。请注意,在这种情况下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 Queueis an Iterablebecause it is a Collectionand 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 Queueis anIterable因为它是 aCollection并且因此需要提供一种iterator()方法,但不应该使用它,或者您首先不应该使用 Queue 。

回答by Matt

if an iterator blocked on hasNextthen the iteration would never finish unless you explicitly broke out of it, this would be quite a strange design.

如果一个迭代器被阻塞,hasNext那么迭代永远不会完成,除非你明确地打破它,这将是一个非常奇怪的设计。

In any case the LinkedBlockingQueuejavadoc has this to say

在任何情况下,LinkedBlockingQueuejavadoc 都有这个说法

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 Iterablewhose iterator()will block, although having a seperate BlockingIteratorwould be foolish. The reason for this is because that lests you use an enhanced forloop, 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.)

我认为在某些情况下有一个人Iterableiterator()意志阻止可能是合理的,尽管有一个单独的人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());
        }
    }