Ich habe Code, in dem ich eine Aufgabe mit Java.util.timer
Plane. Ich habe mich umgesehen und gesehen, dass ExecutorService
dasselbe kann. Haben Sie also in dieser Frage Timer und ExecutorService
verwendet, um Aufgaben zu planen, was bringt es, wenn eine Aufgabe gegenüber einer anderen verwendet wird?
Außerdem wollte ich überprüfen, ob jemand die Klasse Timer
verwendet hat und auf Probleme gestoßen ist, die die Klasse ExecutorService
für sie gelöst hat.
Gemäß Java Concurrency in Practice :
Timer
kann empfindlich auf Änderungen der Systemuhr reagieren, ScheduledThreadPoolExecutor
nicht.Timer
hat nur einen Ausführungsthread, daher kann eine lang laufende Aufgabe andere Aufgaben verzögern. ScheduledThreadPoolExecutor
kann mit einer beliebigen Anzahl von Threads konfiguriert werden. Darüber hinaus haben Sie die volle Kontrolle über erstellte Threads, wenn Sie möchten (indem Sie ThreadFactory
angeben).TimerTask
geworfen werden, beenden diesen einen Thread, wodurch Timer
tot wird : ... dh geplante Aufgaben werden nicht mehr ausgeführt. ScheduledThreadExecutor
fängt nicht nur Laufzeit-Ausnahmen ab, Sie können sie jedoch handhaben, wenn Sie möchten (indem Sie die afterExecute
-Methode von ThreadPoolExecutor
überschreiben). Eine Aufgabe, die eine Ausnahme ausgelöst hat, wird abgebrochen, andere Aufgaben werden jedoch weiterhin ausgeführt.Wenn Sie ScheduledThreadExecutor
anstelle von Timer
verwenden können, tun Sie dies.
Noch eine Sache ... während ScheduledThreadExecutor
nicht in Java 1.4 library verfügbar ist, gibt es einen --- (Backport von JSR 166 (Java.util.concurrent
) to Java 1.2, 1.3, 1.4 mit der Klasse ScheduledThreadExecutor
.
Wenn es Ihnen zur Verfügung steht, ist es schwierig, sich einen Grund vorzustellen nicht um das Executor-Framework Java 5) zu verwenden.
ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
gibt Ihnen ein ScheduledExecutorService
mit einer ähnlichen Funktionalität wie Timer
(dh es wird ein Thread sein), dessen Zugriff jedoch möglicherweise etwas skalierbarer ist (unter der Haube werden eher gleichzeitige Strukturen als vollständige Synchronisation verwendet) wie bei der Klasse Timer
). Die Verwendung eines ScheduledExecutorService
bietet Ihnen auch folgende Vorteile:
newScheduledThreadPoolExecutor()
oder ScheduledThreadPoolExecutor
)Die einzigen Gründe, an Timer
festzuhalten, die mir einfallen, sind:
ExecutorService ist neuer und allgemeiner. Ein Timer ist nur ein Thread, der regelmäßig die von Ihnen geplanten Aufgaben ausführt.
Ein ExecutorService kann ein Thread-Pool sein oder sich sogar auf andere Systeme in einem Cluster verteilen und Dinge wie die einmalige Batch-Ausführung usw. ausführen.
Schauen Sie sich einfach an, was jeder anbietet, um sich zu entscheiden.
Hier sind einige weitere bewährte Methoden zur Verwendung des Timers:
http://tech.puredanger.com/2008/09/22/timer-rules/
Im Allgemeinen würde ich Timer für schnelle und schmutzige Dinge und Executor für eine robustere Nutzung verwenden.
Von der Oracle-Dokumentationsseite auf ScheduledThreadPoolExecutor
Ein ThreadPoolExecutor , der zusätzlich Befehle zur Ausführung nach einer bestimmten Verzögerung oder zur periodischen Ausführung einplanen kann. Diese Klasse ist 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/ThreadPoolExecutor
oder ScheduledThreadPoolExecutor
ist eine offensichtliche Wahl, wenn Sie mehrere Arbeitsthreads haben.
Vorteile von ExecutorService
gegenüber Timer
Timer
kann im Gegensatz zu ExecutorService
die verfügbaren CPU-Kerne nicht nutzen, insbesondere nicht bei mehreren Aufgaben, bei denen Varianten von ExecutorService
wie ForkJoinPool verwendet werdenExecutorService
bietet eine API für die Zusammenarbeit, wenn Sie die Koordination zwischen mehreren Aufgaben benötigen. Angenommen, Sie müssen N Worker-Tasks übergeben und auf die Fertigstellung aller Tasks warten. Sie können es leicht mit invokeAll API erreichen. Wenn Sie dasselbe mit mehreren Timer
Aufgaben erreichen möchten, ist dies nicht einfach.ThreadPoolExecutor bietet eine bessere API für die Verwaltung des Thread-Lebenszyklus.
Thread-Pools lösen zwei unterschiedliche Probleme: Sie bieten in der Regel eine verbesserte Leistung bei der Ausführung einer großen Anzahl von asynchronen Aufgaben, da der Aufwand für den Aufruf pro Aufgabe reduziert ist, und sie bieten eine Möglichkeit zum Binden und Verwalten der Ressourcen, einschließlich der Threads, die beim Ausführen einer Auflistung von 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 die Gemeinkosten 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 Ausnahmebehandlung
Mein Grund, warum ich manchmal Timer gegenüber Executors.newSingleThreadScheduledExecutor () bevorzuge, ist, dass ich viel saubereren Code erhalte, wenn ich den Timer für die Ausführung in 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 Executorservice brauche.