Search code examples
javamultithreadingcollectionsjava.util.concurrent

Why does the iterator.hasNext not work with BlockingQueue?


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.

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)

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.


Solution

  • 1) Is this bad design, or wrong expectation?

    Wrong expectations since it would otherwise violate the contract of Iterator which on Iterator.next() says: Throws: NoSuchElementException - iteration has no more elements. If next() would block the exception would never be thrown.

    2) Is there a way to use the blocking methods

    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.