9

BlockingQueueon で待機している 1 つおよびいくつかのスレッドを考えてみましょうpoll(long, TimeUnit)(おそらく on もtake())。

キューが空になり、待機中のスレッドに待機を停止できることを通知する必要があります。予想される動作は、null返されるか、宣言さInterruptedExceptionれたスローのいずれかです。

Object.notify()LinkedBlockingQueueスレッドが内部ロックを待機しているため、機能しません。

簡単な方法はありますか?

4

3 に答える 3

13

BlockingQueue の Javadoc は良い方法を提案しています:

BlockingQueue は、アイテムが追加されないことを示す「閉じる」または「シャットダウン」操作を本質的にサポートしません。このような機能の必要性と使用法は、実装に依存する傾向があります。たとえば、一般的な戦術は、プロデューサーが特別なエンド オブ ストリーム オブジェクトまたはポイズン オブジェクトを挿入することです。これらのオブジェクトは、コンシューマーによって取得されたときにそれに応じて解釈されます。

于 2010-07-22T08:33:43.190 に答える
5

従来の方法はスレッドを中断することですが、これには当然、スレッドが中断を適切に処理する必要があります。

これは、ブロッキング メソッドの周りで s を適切にキャッチして処理し、それ以外の場合は定期的にフラグInterruptedExceptionをチェック (およびそれに基づいて動作) することを意味します。interrupted

API や言語仕様には、割り込みを特定のキャンセル セマンティクスに関連付けるものはありませんが、実際には、キャンセル以外の目的で割り込みを使用することは脆弱であり、大規模なアプリケーションで維持することは困難です。[...]

中断は通常、キャンセルを実装する最も賢明な方法です。

セクション 7.1.1 のJava Concurrency in Practiceと述べています。同じものからの割り込みを適切に処理する例 (これはプロデューサー スレッドであり、コンシューマーではありませんが、現在のコンテキストではその違いは無視できます):

class PrimeProducer extends Thread {
    private final BlockingQueue<BigInteger> queue;

    PrimeProducer(BlockingQueue<BigInteger> queue) {
        this.queue = queue;
    }

    public void run() {
        try {
            BigInteger p = BigInteger.ONE;
            while (!Thread.currentThread().isInterrupted())
                queue.put(p = p.nextProbablePrime());
        } catch (InterruptedException consumed) {
            /*  Allow thread to exit  */
        }
    }
    public void cancel() { interrupt(); }
}

別の解決策は、タイムアウト パラメータをpoll適度に低く設定することです。これにより、スレッドが定期的にウェイクアップし、割り込みに十分迅速に気付くことができます。それでも、特定のスレッド キャンセル ポリシーに従って、InterruptedException を明示的に処理することは常に良い方法だと思います。

于 2010-07-22T08:15:21.477 に答える
1

あなたのデザインには何か問題があると思います。BlockingQueue を消費するスレッドは、このような方法で中断する必要はありません。一定の間隔で何か他のこと (変数の状態をチェックするなど) を行う必要がある一方で、Queue からも消費する必要がある場合は、2 つのアクションをインターリーブできるように、それに応じてタイムアウトを設定して poll() メソッドを使用する必要があります。

于 2010-07-22T08:23:44.227 に答える