スレッドの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メッセージによって終了します。しかし、私の質問は、このメッセージパッシングを行う適切な方法についてです...
このデザインについては 新しい質問 を参照してください。
永久にループして中断または復帰する代わりに、中断されたステータスを確認することを選択できます。
while (!Thread.currentThread().isInterrupted()) {
try {
doWork();
wait(1000);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
スレッドがExecutorServiceによって管理されるタスクの場合、shutdownNow()を呼び出すだけで、スレッドをすべて正常に終了させることができます。
while (!stop_running) { ... }
...たぶん?スレッドの実行を制御するために、ある種の終了フラグがよく使用されます。
本質的には違います。いつでもbreak
またはreturn
を使用して保釈できます。実際に行うことを確認してください(ある時点で)
問題は、スレッドが何もしないときに何が起こるかです。ループして条件をチェックするだけの場合、スレッドは何もせずにCPU全体を使い果たしてしまいます。したがって、必ずwait
を使用してスレッドをブロックするか、sleep
をオンにする必要がない場合はwait
を使用してください。
「悪い」の定義による。これは、コードを読み取ろうとする人が、ループが終了した理由のために他の場所を探す必要があることを意味します。読みにくくなる場合があります。
この考え方を極端にすると、COMEFROMキーワードになります。 http://en.wikipedia.org/wiki/COMEFROM
10 COMEFROM 40
20 INPUT "WHAT IS YOUR NAME? "; A$
30 PRINT "HELLO, "; A$
40 REM
while (...)
行に終了条件を設定することをお勧めしますが、終了条件は、ループ内のどこかでしかテストできない場合があります。それがbreak
の目的(または例外)です。実際、おそらく、プログラムが終了するまで(_System.exit
_を使用して)スレッドを永久に実行する必要があります。その場合、while (true)
は間違いなく正しいです。
しかし、ループ内に何を入れるべきかについてたぶんあなたは尋ねているでしょう。いくつかのブロッキング操作、つまり、スレッドが他の誰か(別のスレッド、別のプログラム、OS)が何かを実行するのを待つ関数呼び出しを必ず含める必要があります。ロックを使用してプログラミングしている場合、メッセージキューからの読み取り、ファイルまたはネットワークソケットからの読み取り、その他のブロックI/O操作の場合、これは通常_Condition.wait
_です。
sleep
は通常notで十分です。他の参加者がいつ何かをしようとしているのかわからないため、頻繁に目を覚ます(したがって、CPU時間を不必要に消費する)か、めったに起こらない(したがって、タイムリーにイベントに反応しない)ことを避ける方法はありません。スレッドがそのジョブを完了したときに、そのジョブを待機しているユーザーに通知するようにシステムを設計してください(多くの場合、_Condition.signal
_を使用するか、参加することにより)。
通常、ある種のリソースでwait
を実行すると、実際のスレッドの詳細が非表示になります。独自の spinlock を実装したかったようです。
最初に、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--
標準のBlockingQueue
を想定して、あなたは待っているのに忙しいようです。 take
の代わりにpoll
を使用してください。
それ以外は、for (;;)
はwhile (true)
、IMOよりも優れています。
私は通常、「done」というクラス属性のブール値を使用します。その後、スレッドのrunメソッドは次のようになります。
done = false;
while( !done ) {
// ... process stuff
}
その後、done = trueを設定してループを終了できます。これはループの内側から行うことも、他のスレッドがプラグをプルできるようにループを設定する別のメソッドを使用することもできます。
while (true)
は、ループを終了する方法がある場合は悪くありません。そうでない場合、呼び出しは無期限に実行されます。
10000スレッドの場合、while(true)
呼び出しを行うのは悪い習慣です...他のスレッドを実行できるようにするsleep()
をスレッドに持たせたり、スレッドが終了した場合に終了戦略を実行したりしないのはなぜですかランニング?