Java Timer vs ExecutorService?


263

Ich habe Code, mit dem ich eine Aufgabe mit plane java.util.Timer . Ich habe mich umgesehen und gesehen, dass ExecutorServiceich das Gleiche tun kann. Also, diese Frage hier, haben Sie Aufgaben verwendet Timerund ExecutorServicegeplant, was ist der Vorteil einer Verwendung gegenüber einer anderen?

Wollte auch überprüfen, ob jemand die TimerKlasse benutzt hatte und auf irgendwelche Probleme stieß, die dieExecutorService für ihn gelöst wurden.


1
Und wenn Sie noch mehr Funktionen benötigen, schauen Sie sich Quarz an . Sie erhalten viel mehr Jobsteuerung, einschließlich Cron-ähnlicher Zeitplanung, clusterfähiger Zeitplanung und individueller Kontrolle über Jobs (Konzepte wie jeweils ein Lauf, Abhängigkeiten usw.). --Tim
Tim

Antworten:


313

Laut Java Concurrency in der Praxis :

  • Timerkann empfindlich auf Änderungen in der Systemuhr reagieren, ScheduledThreadPoolExecutorist nicht.
  • Timerhat nur einen Ausführungsthread, sodass eine lange laufende Aufgabe andere Aufgaben verzögern kann. ScheduledThreadPoolExecutorkann mit einer beliebigen Anzahl von Threads konfiguriert werden. Darüber hinaus haben Sie die volle Kontrolle über erstellte Threads, wenn Sie möchten (durch Bereitstellung ThreadFactory).
  • Laufzeitausnahmen, die ausgelöst werden, TimerTasktöten diesen einen Thread und machen ihn Timertot :-( ... dh geplante Aufgaben werden nicht mehr ausgeführt. Sie ScheduledThreadExecutorfangen nicht nur Laufzeitausnahmen ab, sondern können sie auch behandeln, wenn Sie möchten (indem Sie die afterExecuteMethode von überschreiben ThreadPoolExecutor). Aufgabe welche Die ausgelöste Ausnahme wird abgebrochen, andere Aufgaben werden jedoch weiterhin ausgeführt.

Wenn Sie ScheduledThreadExecutorstattdessen verwenden können Timer, tun Sie dies.

Noch etwas ... obwohl ScheduledThreadExecutores in der Java 1.4-Bibliothek nicht verfügbar ist, gibt es einen Backport von JSR 166 ( java.util.concurrent) zu Java 1.2, 1.3, 1.4 , der die ScheduledThreadExecutorKlasse hat.


63

Wenn es Ihnen zur Verfügung steht, fällt es Ihnen schwer, sich einen Grund vorzustellen , das Java 5 Executor Framework nicht zu verwenden. Berufung:

ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();

Sie erhalten eine ScheduledExecutorServiceähnliche Funktionalität wie Timer(dh sie wird mit einem Thread ausgeführt), deren Zugriff jedoch möglicherweise etwas skalierbarer ist (unter der Haube werden gleichzeitige Strukturen verwendet, anstatt eine vollständige Synchronisierung wie bei der TimerKlasse durchzuführen). Die Verwendung von ScheduledExecutorServicebietet Ihnen auch Vorteile wie:

  • Sie können es bei Bedarf anpassen (siehe newScheduledThreadPoolExecutor()oder ScheduledThreadPoolExecutorKlasse)
  • Die "einmaligen" Ausführungen können Ergebnisse zurückgeben

Die einzigen Gründe, an denen Timerich festhalten kann, sind:

  • Es ist vor Java 5 verfügbar
  • In J2ME wird eine ähnliche Klasse bereitgestellt, die das Portieren Ihrer Anwendung erleichtern könnte (in diesem Fall wäre es jedoch nicht besonders schwierig, eine gemeinsame Abstraktionsebene hinzuzufügen).

1
Ein weiterer Grund für die Verwendung TimerTaskkann die Verfügbarkeit einer scheduledExecutionTime()Methode sein, für die es keine Entsprechung zu geben scheint ScheduledExecutorService.
Rohit Agarwal

3
Noch ein Hinweis: Ich schreibe diesen Kommentar in 2k17, es gibt kein J2ME mehr. es ist schon tot
Msangel

1
Java Timer-Klasse ist beschissen.
JohnyTex

26

ExecutorService ist neuer und allgemeiner. Ein Timer ist nur ein Thread, der regelmäßig Dinge ausführt, die Sie für ihn geplant haben.

Ein ExecutorService kann ein Thread-Pool sein oder sich sogar auf andere Systeme in einem Cluster verteilen und Dinge wie einmalige Stapelausführung usw. ausführen.

Schauen Sie sich einfach an, was jeder zur Entscheidung anbietet.



8

Von der Oracle-Dokumentationsseite in ScheduledThreadPoolExecutor

Ein ThreadPoolExecutor , der zusätzlich Befehle planen kann, die nach einer bestimmten Verzögerung ausgeführt oder regelmäßig ausgeführt werden sollen. Diese Klasse ist dem Timer vorzuziehen, wenn mehrere Arbeitsthreads benötigt werden oder wenn die zusätzliche Flexibilität oder die Funktionen von ThreadPoolExecutor (die diese Klasse erweitert) erforderlich sind.

ExecutorService/ThreadPoolExecutoroder ScheduledThreadPoolExecutorist eine offensichtliche Wahl, wenn Sie mehrere Arbeitsthreads haben.

Vorteile von ExecutorServiceüberTimer

  1. TimerDie verfügbaren CPU-Kerne können nicht genutzt werden, im Gegensatz ExecutorServicezu mehreren Aufgaben, bei denen VariantenExecutorService wie ForkJoinPool verwendet werden
  2. ExecutorServiceBietet eine kollaborative API, wenn Sie eine Koordination zwischen mehreren Aufgaben benötigen. Angenommen, Sie müssen N Arbeitsaufgaben einreichen und auf den Abschluss aller warten. Sie können dies problemlos mit der invokeAll- API erreichen. Wenn Sie dasselbe mit mehreren TimerAufgaben erreichen möchten, ist dies nicht einfach.
  3. ThreadPoolExecutor bietet eine bessere API für die Verwaltung des Thread-Lebenszyklus.

    Thread-Pools lösen zwei verschiedene Probleme: Sie bieten normalerweise eine verbesserte Leistung bei der Ausführung einer großen Anzahl von asynchronen Aufgaben aufgrund des geringeren Aufrufaufwands pro Aufgabe und bieten eine Möglichkeit zum Begrenzen und Verwalten der Ressourcen, einschließlich Threads, die beim Ausführen einer Sammlung von Aufgaben verbraucht werden Aufgaben. Jeder ThreadPoolExecutor verwaltet auch einige grundlegende Statistiken, z. B. die Anzahl der abgeschlossenen Aufgaben

    Einige Vorteile:

    ein. Sie können den Lebenszyklus von Threads erstellen / verwalten / steuern und den Aufwand für die Thread-Erstellung optimieren

    b. Sie können die Verarbeitung von Aufgaben (Work Stealing, ForkJoinPool, invokeAll) usw. steuern.

    c. Sie können den Fortschritt und den Zustand von Threads überwachen

    d. Bietet einen besseren Mechanismus zur Behandlung von Ausnahmen


5

Mein Grund dafür, Timer manchmal Executors.newSingleThreadScheduledExecutor () vorzuziehen, ist, dass ich viel saubereren Code erhalte, wenn ich den Timer für die Ausführung auf Daemon-Threads benötige.

vergleichen Sie

private final ThreadFactory threadFactory = new ThreadFactory() {
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setDaemon(true);
        return t;
    }
};
private final ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor(threadFactory); 

mit

private final Timer timer = new Timer(true);

Ich mache das, wenn ich nicht die Robustheit eines Executorservices brauche.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.