8

別のスレッドによって生成されたアイテムを消費するスレッドがあるとします。その run メソッドは次のとおりです。inQueue は BlockingQueue です。

boolean shutdown = false;
while (!shutdown) {
    try {
        WorkItem w = inQueue.take();
        w.consume();
    } catch (InterruptedException e) { 
        shutdown = true;
    }
}

さらに、別のスレッドは、この実行中のスレッドを中断することによって、これ以上作業項目がないことを通知します。次の作業項目を取得するためにブロックする必要がない場合、 take() は中断された例外をスローします。つまり、プロデューサーがワーク キューへの書き込みが完了したことを通知した場合、誤って inQueue にいくつかの項目を残したり、割り込みを逃したりする可能性はありますか?

4

5 に答える 5

5

ブロッキングキューの終了を通知する良い方法は、シャットダウンが発生したことを示す「poison」値をキューに送信することです。これにより、キューの期待される動作が確実に尊重されます。キューをクリアすることに関心がある場合は、Thread.interupt()を呼び出すことはおそらく良い考えではありません。

いくつかのコードを提供するには:

boolean shutdown = false;
while (!shutdown) {
    try {
        WorkItem w = inQueue.take();
        if (w == QUEUE_IS_DEAD)
          shutdown = true;
        else
          w.consume();
    } catch (InterruptedException e) { 
        // possibly submit QUEUE_IS_DEAD to the queue
    }
}
于 2009-12-24T03:45:22.793 に答える
2

javadocによると、待機中に中断された場合、take()メソッドはスローされます。InterruptedException

于 2009-12-24T03:49:19.407 に答える
2

私は同じことについて疑問に思い、take()の javadoc を読んで、キューにアイテムがあれば「待機」する必要がないため、キュー内のすべてのアイテムを取得した後にのみ割り込み例外がスローされると信じていました。しかし、私は小さなテストを行いました:

package se.fkykko.slask;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicLong;

public class BlockingQueueTakeTest {

public static void main(String[] args) throws Exception {
    Runner t = new Runner();
    Thread t1 = new Thread(t);
    for (int i = 0; i < 50; i++) {
        t.queue.add(i);
    }
    System.out.println(("Number of items in queue: " + t.queue.size()));
    t1.start();
    Thread.sleep(1000);
    t1.interrupt();
    t1.join();
    System.out.println(("Number of items in queue: " + t.queue.size()));
    System.out.println(("Joined t1. Finished"));

}

private static final class Runner implements Runnable {
    BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(100);
    AtomicLong m_count = new AtomicLong(0);

    @Override
    public void run() {
        try {
            while (true) {
                queue.take();
                System.out.println("Took item " + m_count.incrementAndGet());
                final long start = System.currentTimeMillis();
                while ((System.currentTimeMillis() - start) < 100) {
                    Thread.yield(); //Spin wait
                }
            }
        }
        catch (InterruptedException ex) {
            System.out.println("Interrupted. Count: " + m_count.get());
        }
    }
}

}

ランナーは 10 ~ 11 個のアイテムを取得して終了します。つまり、キューにまだアイテムがある場合でも、take() は InterruptedException をスローします。

概要: 代わりにポイズン ピル アプローチを使用すると、キューにどれだけ残っているかを完全に制御できます。

于 2011-07-08T15:26:56.517 に答える
-1

java.concurrency.utilsパッケージは、並行プログラミングの最高の頭脳によって設計および実装されました。また、スレッドを終了する手段としてスレッドを中断することは、彼らの著書「JavaConcurrencyinPractice」によって明示的に承認されています。そのため、割り込みが原因でキューにアイテムが残っていると、非常に驚​​きます。

于 2009-12-24T03:52:02.350 に答える