6

BlockingQueueでイテレータメソッドを使用しようとしましたが、hasNext()が非ブロッキングであることがわかりました。つまり、要素が追加されるまで待機せず、要素がない場合はfalseを返します。

だからここに質問があります:

  1. これは悪いデザインですか、それとも間違った期待ですか?
  2. BLockingQueueのブロッキングメソッドをその親のCollectionクラスメソッドで使用する方法はありますか(たとえば、あるメソッドがコレクションを期待していた場合、ブロッキングキューを渡し、キューにさらに要素が含まれるまでその処理が待機することを期待できますか)

これがサンプルコードブ​​ロックです

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();
        }
        }
    }

このコードは、最大で1回だけ反復を出力します。

4

5 に答える 5

12

キューでイテレータを使用しないでください。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();
}

AQueueは、メソッドを提供する必要があるIterableためですが、これを使用しないでください。または、そもそもキューを使用しないでください。Collectioniterator()

于 2011-05-27T09:06:13.603 に答える
3

1)これは悪いデザインですか、それとも間違った期待ですか?

Iteratorの契約に違反するため、誤った期待があります。これは、次のようにIterator.next()述べています。ブロックするThrows: NoSuchElementException - iteration has no more elements. 場合next()、例外はスローされません。

2)ブロック方法を使用する方法はありますか

はい。たとえば、クラスを拡張し、nextメソッドをオーバーライドして、hasNext代わりにブロッキングルーチンを使用します。hasNextこの場合は常に戻る必要があることに注意してくださいtrue。これも契約に違反します。

于 2011-05-27T08:54:39.343 に答える
3

イテレータがブロックされている場合、hasNext明示的にイテレータから抜け出さない限り、反復は終了しません。これは非常に奇妙な設計になります。

いずれにせよ、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.
于 2011-05-27T09:15:51.883 に答える
0

別の人を持っているのはばかげているとはいえ、特定の状況下では、Iterableそのiterator()意志をブロックするのは合理的かもしれないと思います。BlockingIteratorこれは、拡張ループを使用する必要がないためです。これによりfor、場合によっては、コードがよりクリーンになります。(特定の状況でそれが達成されない場合は、これをまったく行わないでください。)

for(Request request:requests) process(request);

ただし、イテレータはまだ終了条件から解放されていません。キューが新しいアイテムに対して閉じられ、要素がなくなる、イテレータは終了する必要があります。

ただし、ループがイテレータのnext()メソッドですでにブロックされている場合、キューが閉じている場合に終了する唯一の方法は、例外をスローすることです。これは、周囲のコードが正しく処理する必要があります。これは、javadocコメントで実装がどのように機能するかを非常に明確かつ正確に説明するようにしてください。

于 2013-11-21T02:46:35.433 に答える
-1

LinkedBlockingQueueのIteratorには、hasNext実装としてこれがあります。

  private Node<E> current;

   public boolean hasNext() {
        return current != null;
    }

したがって、これは呼び出しごとにのみ機能します。要素を待機して標準のJavaIteratorイディオムを使用する場合は、メソッドをwhile(true)ループでラップできます。

    while (true) {     
       if(itr.hasNext()) {
          System.out.println(itr.next());
        }
    }
于 2011-05-27T08:58:59.817 に答える