web-dev-qa-db-ja.com

Thread.sleep()VS Executor.scheduleWithFixedDelay()

目標:特定のコードを時々実行します。

質問:パフォーマンスに関して、次の間に大きな違いはありますか?

while(true) {
    execute();
    Thread.sleep(10 * 1000);
}

そして

executor.scheduleWithFixedDelay(runnableWithoutSleep, 0, 10, TimeUnit.SECONDS);

もちろん、後者のオプションはよりコーシャです。それでも、「Thread.sleep()に別れを告げるためにレガシーコードをリファクタリングするのに数日を費やす」という冒険に着手すべきかどうかを知りたいと思います。

更新:このコードは、スーパー/メガ/ハイパー高負荷環境で実行されます。

24
rudgirello

あなたは数十秒と呼ばれる睡眠時間を扱っています。ここでスリープオプションを変更することで可能な節約は、おそらくナノ秒またはマイクロ秒です。

私は毎回後者のスタイルを好みますが、前者を持っていて、それを変更するのに多くの費用がかかる場合、「パフォーマンスの向上」は特に正当な理由ではありません。

[〜#〜] edit [〜#〜] re:8000スレッド

8000スレッドはひどい量です。システムにかかる負荷の量を制御できるようにするために、スケジュールされたエグゼキュータに移動する場合があります。ウェイクアップ時間の変更についてのあなたのポイントは注意すべきことですが、より大きなリスクは、すべてのスレッドがスリープ状態になり、次に連続してウェイクアップし、すべてのシステムリソースを奪い合うことであると主張します。

私はこれらすべてを固定スレッドプールのスケジュールされたエグゼキューターに投入するために時間を費やしました。最も限られたリソース(たとえば、#コア、または#IOパス))と、スロップを取得するためのいくつかのリソースを利用できる数だけ同時に実行します。レイテンシを犠牲にしてスループット。

Thread.sleep()メソッドを使用すると、何が起こっているかを制御するのが非常に難しくなり、スループットおよびレイテンシーの両方を失う可能性があります。

より詳細なアドバイスが必要な場合は、おそらく、何をしようとしているのかをより詳細に説明する必要があります。

11

さまざまなシナリオがあります、

  1. タイマーは、継続的に更新されるタスクのキューを作成します。タイマーが終了すると、すぐにガベージコレクションされない場合があります。したがって、タイマーをさらに作成すると、ヒープにオブジェクトが追加されるだけです。 Thread.sleep()はスレッドを一時停止するだけなので、メモリのオーバーヘッドは非常に低くなります
  2. Timer/TimerTaskは、タスクの実行時間も考慮に入れるため、もう少し正確になります。また、マルチスレッドの問題(デッドロックの回避など)をより適切に処理します。
  3. スレッドが例外を取得して強制終了された場合、それは問題です。しかし、TimerTaskがそれを処理します。前回の実行での失敗に関係なく実行されます
  4. TimerTaskの利点は、意図をはるかによく表現し(つまり、コードの可読性)、cancel()機能がすでに実装されていることです。

参照は ここ から取得されます

2
Code_Mode

Javaバージョンについては言及していないので、状況が変わる可能性があります。

Javaのソースコードから思い出すと、主な違いは、内部での記述方法です。

Sun Java 1.6の場合、2番目のアプローチを使用すると、ネイティブコードも待機して通知システムへの呼び出しをもたらします。よりスレッド効率が高く、CPUに優しい方法で。

しかし、再びコントロールを失い、コードの予測が難しくなります。10秒間スリープしたいと考えてください。

したがって、より予測可能性が必要な場合は、オプション1を使用できます。

また、補足として、レガシーシステムでは、このような問題が発生した場合(80%の確率で、より良い方法があります)、魔法数が理由で存在するため(残りの20%)、次の場所で変更してください。自身のリスク :)

1
rock_win

あなたは「メガ...高負荷環境」で実行していると言ったので、私が正しく理解していれば、コード例のように多くのそのようなスレッドが同時にスリープしています。スレッドを強制終了して新しいスレッドを作成するよりも、スレッドを再利用するのにかかるCPU時間は短く、リファクタリングによってスレッドを再利用できる場合があります。

corePoolSizeが1より大きい ScheduledThreadPoolExecutor を使用して、スレッドプールを作成できます。次に、そのスレッドプールで scheduleWithFixedDelay を呼び出すと、スレッドが利用可能な場合は再利用されます。

この変更により、スレッドが破棄および作成されるのではなく再利用されるため、CPU使用率が低下する可能性がありますが、低下の程度は、実行中のタスク、プール内のスレッドの数などによって異なります。メモリ使用量も低下します。一度にアイドル状態になっているスレッドが少なくなるため、タスクの重複が発生します。

0
Max