Java Timer vs ExecutorService?
-
03-07-2019 - |
Question
J'ai un code dans lequel je planifie une tâche à l'aide de java.util.timer
. Je regardais autour de moi et j'ai vu que ExecutorService
pouvait faire la même chose. Donc, cette question ici, avez-vous utilisé Timer et ExecutorService
pour planifier des tâches, quel est l'avantage d'une utilisation par rapport à une autre?
Voulait également vérifier si quelqu'un avait utilisé la classe Timer
et rencontré des problèmes que le ExecutorService
avait résolus pour eux.
La solution
Selon la concurrence de Java en pratique :
-
Timer
peut être sensible aux modifications de l'horloge système.ScheduledThreadPoolExecutor
ne l'est pas. -
Timer
n'a qu'un seul thread d'exécution. Par conséquent, une tâche de longue durée peut retarder d'autres tâches.ScheduledThreadPoolExecutor
peut être configuré avec un nombre quelconque de threads. De plus, vous avez un contrôle total sur les threads créés, si vous le souhaitez (en fournissantThreadFactory
). - Les exceptions d'exécution levées dans
TimerTask
tuent ce thread, rendant ainsiTimer
mort :-( ... c'est-à-dire que les tâches planifiées ne s'exécutent plus.ScheduledThreadExecutor
non seulement attrape les exceptions d'exécution, mais vous permet de les gérer si vous le souhaitez (en remplaçant la méthodeafterExecute
à partir deThreadPoolExecutor
). La tâche qui a lancé l'exception sera annulée, d'autres tâches continueront à s'exécuter.
Si vous pouvez utiliser ScheduledThreadExecutor
au lieu de Minuteur
, faites-le.
Encore une chose ... Bien que ScheduledThreadExecutor
ne soit pas disponible dans la bibliothèque Java 1.4, il existe un Backport de JSR 166 ( java.util.concurrent
) vers Java 1.2, 1.3, 1.4 , qui possède la classe ScheduledThreadExecutor
.
Autres conseils
S'il est disponible, il est difficile de trouver une raison de ne pas utiliser le framework d'exécution Java 5. Appel:
ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
vous donnera un ScheduledExecutorService
avec des fonctionnalités similaires à Timer
(c’est-à-dire qu’il sera mono-threaded) mais dont l’accès peut être légèrement plus évolutif (sous le capot, il utilise des structures concurrentes plutôt qu'une synchronisation complète comme avec la classe Timer
. L'utilisation d'un ScheduledExecutorService
vous offre également des avantages tels que:
- Vous pouvez le personnaliser si nécessaire (voir la classe
newScheduledThreadPoolExecutor ()
ou laScheduledThreadPoolExecutor
- Les exécutions uniques peuvent renvoyer des résultats
Les seules raisons pour lesquelles je reste fidèle à Minuteur
sont les suivantes:
- Il est disponible avant Java 5
- Une classe similaire est fournie dans J2ME, ce qui pourrait faciliter le portage de votre application (mais il ne serait pas très difficile d'ajouter une couche d'abstraction commune dans ce cas)
ExecutorService est plus récent et plus général. Une minuterie est juste un fil qui exécute périodiquement les choses que vous avez programmées pour cela.
Un ExecutorService peut être un pool de threads, voire même être réparti sur d'autres systèmes d'un cluster et effectuer des opérations telles que l'exécution par lots ponctuelle, etc.
Il suffit de regarder ce que chacun propose de décider.
Voici d'autres bonnes pratiques concernant l'utilisation du minuteur:
http://tech.puredanger.com/2008/09/22 / timer-rules /
En général, j'utiliserais Timer pour les commandes rapides et sales et Executor pour une utilisation plus robuste.
La raison pour laquelle je préfère parfois préférer Timer à Executors.newSingleThreadScheduledExecutor () est que je reçois un code beaucoup plus propre lorsque j'ai besoin du minuteur pour qu'il s'exécute sur des threads de démon.
comparer
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);
avec
private final Timer timer = new Timer(true);
Je le fais quand je n'ai pas besoin de la robustesse d'un service d'exécution.
À partir de la page de documentation d'Oracle sur ScheduledThreadPoolExecutor
Un ThreadPoolExecutor qui peut en outre planifier l'exécution de commandes après un délai donné ou périodiquement. Cette classe est préférable à Minuteur lorsque plusieurs threads de travail sont requis ou lorsque la flexibilité ou les fonctionnalités supplémentaires de ThreadPoolExecutor (que cette classe étend) sont requises.
ExecutorService / ThreadPoolExecutor
ou ScheduledThreadPoolExecutor
est un choix évident lorsque vous avez plusieurs threads de travail.
Avantages de ExecutorService
sur Minuterie
-
Timer
ne peut tirer parti des cœurs de processeur disponibles, contrairement àExecutorService
, en particulier pour plusieurs tâches utilisant des variantes deExecutorService
comme ForkJoinPool -
ExecutorService
fournit une API collaborative si vous avez besoin d'une coordination entre plusieurs tâches. Supposons que vous deviez soumettre un nombre N de tâches de travail et attendre qu'elles soient toutes terminées. Vous pouvez facilement y parvenir avec invokeAll API. Si vous souhaitez obtenir le même résultat avec plusieurs tâchesTimer
, cela ne sera pas simple. -
ThreadPoolExecutor fournit une meilleure API pour la gestion du cycle de vie des threads.
Les pools de threads traitent deux problèmes différents: ils offrent généralement de meilleures performances lors de l’exécution d’un grand nombre de tâches asynchrones, en raison de la réduction du temps d’appel par tâche, et ils permettent de limiter et de gérer les ressources, y compris les threads, utilisées lors de l’exécution. une collection de tâches. Chaque ThreadPoolExecutor gère également des statistiques de base, telles que le nombre de tâches terminées.
Peu d'avantages:
a. Vous pouvez créer / gérer / contrôler le cycle de vie de Threads & amp; optimiser les coûts de création de threads
b. Vous pouvez contrôler le traitement des tâches (Work Stealing, ForkJoinPool, invokeAll), etc.
c. Vous pouvez surveiller la progression et la santé des threads
d. Fournit un meilleur mécanisme de gestion des exceptions