Timer & TimerTask versus Thread + Sleep in Java

102

Ich fand hier ähnliche Fragen, aber es gab keine Antworten zu meiner Zufriedenheit. Also die Frage noch einmal umformulieren -

Ich habe eine Aufgabe, die regelmäßig erledigt werden muss (z. B. Intervalle von 1 Minute). Was ist der Vorteil der Verwendung von Timertask & Timer, anstatt einen neuen Thread zu erstellen, der eine Endlosschleife mit Schlaf hat?

Code-Snippet mit Timertask-

TimerTask uploadCheckerTimerTask = new TimerTask(){

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

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

Code-Snippet mit Thread und sleep-

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

Ich muss mir wirklich keine Sorgen machen, wenn ich bestimmte Zyklen verpasse, wenn die Ausführung der Logik länger als die Intervallzeit dauert.

Bitte kommentieren Sie dies ..

Update:
Kürzlich habe ich einen weiteren Unterschied zwischen der Verwendung von Timer und Thread.sleep () festgestellt. Angenommen, die aktuelle Systemzeit ist 11:00 Uhr. Wenn wir die Systemzeit aus irgendeinem Grund auf 10:00 Uhr zurücksetzen, stoppt der Timer die Ausführung der Aufgabe, bis sie 11:00 Uhr erreicht hat, während die Thread.sleep () -Methode die Ausführung der Aufgabe ungehindert fortsetzt. Dies kann ein wichtiger Entscheidungsträger bei der Entscheidung sein, was zwischen diesen beiden verwendet werden soll.

Keshav
quelle
21
Geschäftsordnung: Timer und TimerTask sind veraltet und wurden effektiv durch ExecutorService ersetzt, obwohl Ihr Punkt noch besteht.
Skaffman
Vielen Dank für den Tipp, ich habe mich für ExecutorService entschieden :)
Keshav
Vielen Dank für die Antworten, hat mir sicherlich mehr Verständnis gegeben!
Keshav
6
Der Timer ist nicht veraltet und wird bevorzugt, wenn nur ein einziger Thread benötigt wird. ( java.sun.com/javase/6/docs/api/java/util/Timer.html )
Justin
2
Timer und TimerTask sind weiterhin in JME-Umgebungen nützlich, in denen ExecutorService nicht vorhanden ist (da JME Java 1.3 basiert ...).
ン ー パ ー. ァ ァ ミ

Antworten:

66

Der Vorteil von TimerTask besteht darin, dass es Ihre Absicht viel besser ausdrückt (dh die Lesbarkeit des Codes) und die Funktion cancel () bereits implementiert ist.

Beachten Sie, dass es sowohl in kürzerer Form als auch in Ihrem eigenen Beispiel geschrieben werden kann:

Timer uploadCheckerTimer = new Timer(true);
uploadCheckerTimer.scheduleAtFixedRate(
    new TimerTask() {
      public void run() { NewUploadServer.getInstance().checkAndUploadFiles(); }
    }, 0, 60 * 1000);
Zed
quelle
Wenn der Timer für den täglichen Gebrauch verwendet wird, zu 2 bestimmten Zeiten, 21 Uhr und 9 Uhr, ... wie werden die Werte angegeben? auf dem Code oben ... @Zed?
Gumuruh
12

Timer / TimerTask berücksichtigt auch die Ausführungszeit Ihrer Aufgabe, sodass sie etwas genauer ist. Und es behandelt besser Multithreading-Probleme (wie das Vermeiden von Deadlocks usw.). Und natürlich ist es normalerweise besser, gut getesteten Standardcode anstelle einer hausgemachten Lösung zu verwenden.

MartinStettner
quelle
5

Ich weiß nicht warum, aber ein Programm, das ich schrieb, verwendete Timer und seine Heap-Größe nahm ständig zu, nachdem ich es in Thread / Schlaf-Problem geändert hatte.

Qandeel
quelle
9
Der Timer erstellt eine Warteschlange mit Aufgaben, die ständig aktualisiert wird. Wenn der Timer fertig ist, wird möglicherweise nicht sofort Müll gesammelt. Wenn Sie also mehr Timer erstellen, werden dem Heap nur mehr Objekte hinzugefügt. Thread.sleep () pausiert nur den Thread, sodass der Speicheraufwand extrem gering wäre.
Darryl Gerrow
4

Wenn Ihr Thread eine Ausnahme erhält und getötet wird, ist dies ein Problem. Aber TimerTask wird sich darum kümmern. Es wird unabhängig von einem Fehler im vorherigen Lauf ausgeführt.

Stapel Popper
quelle
4

Aus der Timer Dokumentation :

In Java 5.0 wurde das Paket java.util.concurrent eingeführt. Eines der darin enthaltenen Dienstprogramme zur Parallelität ist der ScheduledThreadPoolExecutor, ein Thread-Pool zum wiederholten Ausführen von Aufgaben mit einer bestimmten Rate oder Verzögerung. Es ist effektiv ein vielseitigerer Ersatz für die Timer / TimerTask-Kombination, da es mehrere Service-Threads zulässt, verschiedene Zeiteinheiten akzeptiert und keine Unterklasse TimerTask erfordert (nur Runnable implementieren). Wenn Sie ScheduledThreadPoolExecutor mit einem Thread konfigurieren, entspricht dies dem Timer.

Also ScheduledThreadExecutorlieber als Timer:

  • TimerVerwendet einen einzelnen Hintergrundthread, mit dem alle Aufgaben des Timers nacheinander ausgeführt werden. Aufgaben sollten also schnell erledigt werden, da sonst die Ausführung nachfolgender Aufgaben verzögert wird. Im Falle von können ScheduledThreadPoolExecutorwir jedoch eine beliebige Anzahl von Threads konfigurieren und durch Bereitstellung auch die volle Kontrolle haben ThreadFactory.
  • Timerkann empfindlich auf die Systemuhr reagieren, da sie eine Object.wait(long)Methode verwendet. Ist ScheduledThreadPoolExecutoraber nicht.
  • In TimerTask ausgelöste Laufzeitausnahmen töten diesen bestimmten Thread und machen Timer tot, wo wir das verarbeiten können, ScheduledThreadPoolExecutordamit die anderen Aufgaben nicht beeinträchtigt werden.
  • TimerBietet eine cancelMethode zum Beenden des Timers und zum Verwerfen geplanter Aufgaben, beeinträchtigt jedoch nicht die aktuell ausgeführte Aufgabe und lässt sie beenden. Wenn der Timer jedoch als Daemon-Thread ausgeführt wird, wird er beendet, sobald alle Benutzer-Threads ausgeführt wurden, unabhängig davon, ob wir ihn abbrechen oder nicht.

Timer vs Thread.sleep

Timer nutzt Object.waitund unterscheidet sich vonThread.sleep

  1. Ein wartender ( wait) Thread kann notifyvon einem anderen Thread benachrichtigt (verwendet ) werden, ein schlafender Thread jedoch nicht, er kann nur unterbrochen werden.
  2. Ein Warten (und Benachrichtigen) muss in einem Block erfolgen, der auf dem Monitorobjekt synchronisiert ist, während dies im Ruhezustand nicht der Fall ist.
  3. Während der Schlaf die Sperre nicht aufhebt, wird durch das Warten die Sperre für das aufgerufene Objekt aufgehoben.
akhil_mittal
quelle
Sehr nützliche Informationen. Außerdem kann die Verwendung von Thread.sleep in einer Endlosschleife zu einer hohen CPU-Auslastung bei geringen Zeitverzögerungen führen.
Amir Fo
3

Es gibt ein entscheidendes Argument gegen die Verwaltung dieser Aufgabe mithilfe von Java-Threads und sleep-Methoden. Sie verwenden while(true), um unbegrenzt in der Schleife zu bleiben und den Thread in den Ruhezustand zu versetzen, indem Sie ihn in den Ruhezustand versetzen. Was ist, wenn NewUploadServer.getInstance().checkAndUploadFiles();einige synchronisierte Ressourcen belegt werden ? Andere Threads können nicht auf diese Ressourcen zugreifen. Es kann zu einem Hunger kommen, der Ihre gesamte Anwendung verlangsamen kann. Diese Art von Fehlern ist schwer zu diagnostizieren und es ist eine gute Idee, ihre Existenz zu verhindern.

Der andere Ansatz löst die Ausführung des für Sie wichtigen Codes aus, dh NewUploadServer.getInstance().checkAndUploadFiles();indem Sie die run()Methode von aufrufen, TimerTaskwährend andere Threads in der Zwischenzeit die Ressourcen verwenden.

Boris Pavlović
quelle
16
Ich verstehe dieses Argument nicht. Beide Auswahlmöglichkeiten starten dieselbe Methode von einem Thread aus. Beide Auswahlmöglichkeiten befinden sich in einem Thread, während sie auf die Ausführung warten. Es wird keine Hungerunterschiede zwischen den beiden Möglichkeiten geben.
Samstag,
2

Ich glaube, ich verstehe Ihr Problem, ich sehe etwas sehr Ähnliches. Ich habe wiederkehrende Timer, einige alle 30 Minuten und einige alle paar Tage. Nach dem, was ich gelesen habe und den Kommentaren, die ich sehe, sieht es so aus, als würde die Garbage Collection niemals ausgeführt, da alle Aufgaben niemals abgeschlossen sind. Ich würde denken, dass die Speicherbereinigung ausgeführt wird, wenn ein Timer im Ruhezustand ist, aber ich sehe es nicht und laut Dokumentation nicht.

Ich denke, dass das Laichen neuer Threads abgeschlossen ist und die Speicherbereinigung ermöglicht.

Jemand, bitte beweise mir das Gegenteil. Das Umschreiben von dem, was ich geerbt habe, wird ein Schmerz sein.

Ken
quelle