28

while (true) { ... }スレッドのループは悪いですか?代替手段は何ですか?

アップデート; 私がやろうとしていること...

私は最大10,000のスレッドを持っており、それぞれがプライベートキューからのメッセージを消費しています。メッセージを1つずつ生成し、それらを正しいコンシューマーのキューに入れるスレッドが1つあります。各コンシューマスレッドは無期限にループし、キューに表示されるメッセージをチェックして処理します。

Consumer.javaの内部:

@Override
public void run() {
    while (true) {
        Message msg = messageQueue.poll();
        if (msg != null) {
            ... // do something with the message
        }
    }
}

プロデューサーは、メッセージをコンシューマーメッセージキュー内に急速に配置しています(1秒あたり数百万メッセージ)。消費者はこれらのメッセージをできるだけ速く処理する必要があります!

注:はwhile (true) { ... }、最後のメッセージとしてプロデューサーによって送信されたKILLメッセージによって終了します。しかし、私の質問は、このメッセージパッシングを行う適切な方法についてです...

このデザインについては、新しい質問をご覧ください。

4

12 に答える 12

19

永久にループして中断または復帰する代わりに、中断されたステータスを確認することを選択できます。

while (!Thread.currentThread().isInterrupted()) {
    try {
        doWork();
        wait(1000);
    } catch (InterruptedException ex) {
        Thread.currentThread().interrupt();
    }
}

スレッドがExecutorServiceによって管理されるタスクである場合は、shutdownNow()を呼び出すだけで、すべてのスレッドを正常に終了させることができます。

于 2010-07-29T22:03:49.293 に答える
9
while (!stop_running) { ... }

...多分?スレッドの実行を制御するために、ある種の終了フラグがよく使用されます。

于 2010-07-29T21:48:34.780 に答える
7

本質的ではありません。breakまたはを使用して、いつでも保釈できますreturn。(ある時点で)実際に行うことを確認してください

問題は、スレッドが何もしない場合に何が起こるかということです? ループして条件をチェックするだけでは、スレッドは何もせずに CPU 全体を使い果たします。したがってwait、スレッドをブロックするために使用するか、sleep何もする必要がない場合は必ず使用してくださいwait

于 2010-07-29T21:49:12.717 に答える
3

「悪い」の定義によります。これは、コードを読み取ろうとする人が、ループが終了したために別の場所を探す必要があることを意味します。そのため、読みにくくなる可能性があります。

この極端な考え方が、COMEFROM キーワードにつながっています。 http://en.wikipedia.org/wiki/COMEROM

10 COMEFROM 40
20 INPUT "WHAT IS YOUR NAME? "; A$
30 PRINT "HELLO, "; A$
40 REM
于 2010-07-29T21:58:11.650 に答える
1

while (true)ループを終了する方法があれば悪くはありません。そうでない場合、呼び出しは無期限に実行されます。

10000スレッドの場合、while(true)呼び出しを行うのは悪い習慣です...sleep()他のスレッドを実行できるようにするためのスレッドや、スレッドの実行が終了した場合の出口戦略がないのはなぜですか?

于 2010-07-29T22:07:48.623 に答える
1

wait通常、実際のスレッドの詳細が見えないように、なんらかのリソースで作業を行いたいと思うでしょう。独自のspinlockを実装したかったようです。

これは、私がグーグルで見つけたロックに関するチュートリアルです。

于 2010-07-29T21:46:55.607 に答える
1

回線上にwhile (...)終了条件を設定することをお勧めしますが、終了条件はループの奥深くでしかテストできない場合があります。次に、それがbreak(または例外)の目的です。実際、プログラムが終了するまでスレッドを永久に実行する必要があるかもしれません (でSystem.exit); それならwhile (true)間違いなく正しいです。

しかし、ループ内に何を入れるべきかについて質問しているかもしれません。ブロッキング操作、つまり、スレッドが他の誰か (別のスレッド、別のプログラム、OS) が何かをするのを待つ関数呼び出しを含めるようにする必要があります。これは通常Condition.wait、ロックを使用してプログラミングしている場合、メッセージ キューから読み取っている場合、ファイルやネットワーク ソケットから読み取っている場合、またはその他のブロッキング I/O 操作を行っている場合です。

sleep一般的には十分ではないことに注意してください。他の参加者がいつ何かを行うかを知ることはできないため、頻繁に起きすぎたり (不必要に CPU 時間を浪費したり)、ほとんど起きなかったり (イベントにタイムリーに反応しない) することを避ける方法はありません。スレッドがそのジョブを完了したときに、そのジョブを待機しているユーザーに通知するようにシステムを常に設計してください (多くの場合、参加して、Condition.signalまたは参加して)。

于 2010-07-29T21:59:17.660 に答える
0

私は通常、「done」と呼ばれるクラス属性ブール値を使用します。その後、スレッドの実行メソッドは次のようになります。

done = false;
while( !done ) {
    // ... process stuff
}

次に、done = trueを設定して、ループを強制終了できます。これはループの内側から実行できます。または、他のスレッドがプラグをプルできるように、ループを設定する別のメソッドを使用することもできます。

于 2010-07-29T22:06:48.303 に答える
0

標準的なBlockingQueue. takeの代わりに使用しpollます。

それ以外は、IMOfor (;;)よりも優れています。while (true)

于 2010-07-29T23:31:55.943 に答える
0

まず最初に、Dough Lea によるこの問題への率直な答え:

変数の値を待機する裸のスピンを使用することは、ほとんど良い考えではありません。Thread.onSpinWait、Thread.yield、および/またはブロッキング同期を使用して、特にシステムにコアよりも多くのスレッドがある場合に、「最終的に」時間が長くなる可能性があるという事実にうまく対処します。

http://gee.cs.oswego.edu/dl/html/j9mm.html

Thead.onSpinWait は Java 9 で導入されました。次のようになります。

while (true) {
    while (messageQueue.peek() == null) {
       Thread.onSpinWait();
    }
    // do something with the message
}

スピン待機ループ コンストラクトの各反復内でこのメソッドを呼び出すことにより、呼び出し元のスレッドは、それがビジー待機中であることをランタイムに示します。ランタイムは、スピン待機ループ構築の呼び出しのパフォーマンスを改善するためのアクションを実行する場合があります。

https://docs.oracle.com/javase/9​​/docs/api/java/lang/Thread.html#onSpinWait--

于 2018-09-23T09:54:53.100 に答える
-2

あなたが話していることを私がするなら、私はこれを試します:

private Object lock = new Object();    

public void run(){
    while(true){
        synchronized(lock){
            Message msg = messageQueue.poll();
            if (msg != null) {
                ... // do something with the message
            }else{
                try{
                    lock.wait();
                }catch(InterruptedException e){
                    e.printStackTrace();
                    continue;
                }
            }
        }
    }
}

これにより、messageQueue で同時変更例外が発生しないようにすることができます。また、メッセージがない場合は while(true) ループで CPU 時間を使用しません。ここで、messageQueue に何かを追加するときにlock.notifyAll()、スレッドが再び実行されることを認識できるように呼び出すことができることを確認する必要があります。

于 2010-07-29T22:21:03.950 に答える