web-dev-qa-db-ja.com

タイマーとTimerTask vsスレッド+スリープJava

ここでも同様の質問がありましたが、満足できる答えはありませんでした。質問を言い換えると

定期的に(1分間隔など)実行する必要があるタスクがあります。スリープで無限ループを持つ新しいスレッドを作成するのではなく、Timertask&Timerを使用してこれを行う利点は何ですか?

Timertask-を使用したコードスニペット

TimerTask uploadCheckerTimerTask = new TimerTask(){

 public void run() {
  NewUploadServer.getInstance().checkAndUploadFiles();
 }
};

Timer uploadCheckerTimer = new Timer(true);
uploadCheckerTimer.scheduleAtFixedRate(uploadCheckerTimerTask, 0, 60 * 1000);

スレッドとスリープを使用したコードスニペット-

Thread t = new Thread(){
 public void run() {
  while(true) {
   NewUploadServer.getInstance().checkAndUploadFiles();
   Thread.sleep(60 * 1000);
  }
 }
};
t.start();

ロジックの実行にインターバル時間がかかる場合、特定のサイクルを逃しても心配する必要はありません。

これについてコメントしてください。

更新:
最近、TimerとThread.sleep()の使用に別の違いが見つかりました。現在のシステム時刻が午前11:00であるとします。何らかの理由でシステム時間を午前10:00にロールバックすると、タイマーは午前11:00に達するまでタスクの実行を停止しますが、Thread.sleep()メソッドはタスクを妨げずに実行し続けます。これは、これら2つの間で何を使用するかを決定する際の主要な意思決定者となります。

102
Keshav

TimerTaskの利点は、意図をより良く表現すること(つまり、コードを読みやすくすること)であり、すでにcancel()機能が実装されていることです。

独自の例と同様に短い形式で記述できることに注意してください。

Timer uploadCheckerTimer = new Timer(true);
uploadCheckerTimer.scheduleAtFixedRate(
    new TimerTask() {
      public void run() { NewUploadServer.getInstance().checkAndUploadFiles(); }
    }, 0, 60 * 1000);
67
Zed

Timer/TimerTaskでは、タスクの実行時間も考慮されるため、もう少し正確になります。また、マルチスレッドの問題(デッドロックの回避など)をより適切に処理します。そしてもちろん、自家製のソリューションの代わりに、十分にテストされた標準コードを使用する方が通常は優れています。

13
MartinStettner

理由はわかりませんが、書いているプログラムがタイマーを使用していて、スレッド/スリープの問題を解決すると、ヒープサイズが絶えず増加していました。

5
Qandeel

スレッドが例外を取得して強制終了する場合、それは問題です。ただし、TimerTaskが処理します。以前の実行の失敗に関係なく実行されます。

4
Stack Popper

Timerから ドキュメント

Java 5.0はJava.util.concurrentパッケージを導入し、その中の同時実行ユーティリティの1つは、指定されたレートまたは遅延でタスクを繰り返し実行するためのスレッドプールであるScheduledThreadPoolExecutorです。複数のサービススレッドを許可し、さまざまな時間単位を受け入れ、TimerTaskのサブクラス化を必要としないため(Runnableを実装するだけ)、Timer/TimerTaskの組み合わせをより効果的に置き換えます。 1つのスレッドでScheduledThreadPoolExecutorを構成すると、Timerと同等になります。

したがって、ScheduledThreadExecutorではなくTimerを優先します。

  • Timerは、タイマーのすべてのタスクを順番に実行するために使用される単一のバックグラウンドスレッドを使用します。したがって、タスクはすぐに完了する必要があります。そうでない場合、後続のタスクの実行が遅れます。ただし、ScheduledThreadPoolExecutorの場合、任意の数のスレッドを構成でき、ThreadFactoryを提供することで完全に制御することもできます。
  • Timerは、Object.wait(long)メソッドを使用するため、システムクロックの影響を受ける可能性があります。しかし、ScheduledThreadPoolExecutorはそうではありません。
  • TimerTaskでスローされたランタイム例外はその特定のスレッドを強制終了するため、ScheduledThreadPoolExecutorでそれを処理できるため、他のタスクに影響を与えないようにTimerを停止します。
  • Timerは、タイマーを終了し、スケジュールされたタスクを破棄するcancelメソッドを提供しますが、現在実行中のタスクに干渉せずに終了します。ただし、タイマーがデーモンスレッドとして実行されている場合、キャンセルするかどうかにかかわらず、すべてのユーザースレッドの実行が終了するとすぐに終了します。

タイマーとThread.sleep

タイマーはObject.waitを使用し、Thread.sleepとは異なります

  1. 待機中の(wait)スレッドは別のスレッドから(notifyを使用して)通知できますが、スリープ中のスレッドには通知できません。割り込みのみ可能です。
  2. モニターオブジェクトで同期されたブロックで待機(および通知)が発生する必要がありますが、スリープは発生しません。
  3. スリープはロックを解除しませんが、待機はオブジェクトのロックが解除されるのを待ちます。
3
i_am_zero

私はあなたの問題を理解していると思います、私は非常に似たようなものを見ています。タイマーは30分ごと、数日ごとに繰り返し使用されます。私が読んだことと私が見たコメントから、すべてのタスクが完了しないため、ガベージコレクションは実行されないように見えます。タイマーがスリープ状態のときにガベージコレクションが実行されると思いますが、私はそれを見ていませんし、ドキュメントによるとそれはありません。

新しいスレッドの生成が完了し、ガベージコレクションが可能になると思います。

誰かが間違っていることを証明してください、私が受け継いだものを書き直すのは苦痛になるでしょう。

1
Ken