J'ai un code où je programme une tâche en utilisant Java.util.timer
. Je cherchais autour de moi et j'ai vu ExecutorService
en faire autant. 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
résolvait pour lui.
Selon Java Concurrency in Practice :
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, une tâche longue peut donc 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 voulez (en fournissant ThreadFactory
).TimerTask
tuent ce fil, rendant ainsi Timer
mort : ... c'est-à-dire que les tâches planifiées ne s'exécuteront plus. ScheduledThreadExecutor
ne capture pas seulement les exceptions d'exécution, mais elle vous permet de les gérer si vous le souhaitez (en surchargeant la méthode afterExecute
de ThreadPoolExecutor
). La tâche dont l'exception a été levée sera annulée, mais d'autres tâches continueront à s'exécuter.Si vous pouvez utiliser ScheduledThreadExecutor
au lieu de Timer
, faites-le.
Une dernière chose ... Bien que ScheduledThreadExecutor
ne soit pas disponible dans la bibliothèque Java 1.4, il existe un --- (portage de JSR 166 (Java.util.concurrent
) À Java 1.2, 1.3, 1.4 , qui a la classe ScheduledThreadExecutor
.
S'il est disponible, il est alors difficile de trouver une raison pas d'utiliser le framework = Java 5). Appeler:
ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
vous donnera un ScheduledExecutorService
avec une fonctionnalité similaire à Timer
(c’est-à-dire qu’il sera mono-thread), mais dont l’accès sera peut-être légèrement plus évolutif (sous le capot, il utilise des structures concurrentes plutôt que la synchronisation complète comme avec la classe Timer
). L'utilisation de ScheduledExecutorService
vous donne également des avantages tels que:
newScheduledThreadPoolExecutor()
ou la classe ScheduledThreadPoolExecutor
)Les seules raisons pour lesquelles je reste fidèle à Timer
sont les suivantes:
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 quelques bonnes pratiques supplémentaires concernant l'utilisation du minuteur:
http://tech.puredanger.com/2008/09/22/timer-rules/
En général, j'utiliserais Timer pour les trucs rapides et sales et Executor pour une utilisation plus robuste.
Depuis la page de documentation Oracle sur ScheduledThreadPoolExecutor
Un ThreadPoolExecutor pouvant en outre planifier l'exécution de commandes après un délai donné ou périodiquement. Cette classe est préférable à Timer lorsque plusieurs threads de travail sont nécessaires ou lorsque la flexibilité ou les capacités supplémentaires de ThreadPoolExecutor (auquel cette classe est étendue) sont nécessaires.
ExecutorService/ThreadPoolExecutor
ou ScheduledThreadPoolExecutor
est un choix évident lorsque vous avez plusieurs threads de travail.
Les avantages de ExecutorService
sur Timer
Timer
ne peut tirer parti des cœurs de processeur disponibles contrairement à ExecutorService
, en particulier avec plusieurs tâches utilisant des variantes de ExecutorService
comme ForkJoinPoolExecutorService
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 voulez obtenir le même résultat avec plusieurs tâches Timer
, ce ne serait 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 de la charge d'appel par tâche, et ils permettent de lier et de gérer les ressources, y compris les threads, utilisées lors de l'exécution d'une collection de fichiers. les tâches. Chaque ThreadPoolExecutor gère également des statistiques de base, telles que le nombre de tâches terminées.
Peu d'avantages:
une. Vous pouvez créer/gérer/contrôler le cycle de vie des threads et optimiser les frais généraux de création de thread
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
ré. Fournit un meilleur mécanisme de gestion des exceptions
La raison pour laquelle je préfère parfois préférer Timer à Executors.
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.