Java Timer vs ExecutorService?

263

J'ai du code où je planifie une tâche en utilisant java.util.Timer. Je regardais autour de moi et j'ai vu que l' ExecutorServiceon pouvait faire de même. Donc, cette question ici, avez-vous utilisé Timeret ExecutorServicepour planifier des tâches, quel est l'avantage d'une utilisation par rapport à une autre?

Je voulais également vérifier si quelqu'un avait utilisé la Timerclasse et rencontré des problèmes qui les avaient ExecutorServicerésolus.

Kal
la source
1
Et si vous avez besoin de quelque chose d'encore plus de fonctionnalités, consultez le quartz . Il vous donne beaucoup plus de contrôle sur les travaux, y compris la planification cron, la planification sensible aux clusters, le contrôle individualisé des travaux (concepts tels qu'une exécution à la fois, dépendances, etc.). --Tim
Tim

Réponses:

313

Selon Java Concurrency en pratique :

  • Timerpeut être sensible aux changements d'horloge du système, ScheduledThreadPoolExecutorn'est-ce pas.
  • Timern'a qu'un seul thread d'exécution, donc une tâche de longue durée peut retarder d'autres tâches. ScheduledThreadPoolExecutorpeut être configuré avec un nombre illimité de threads. De plus, vous avez un contrôle total sur les threads créés, si vous le souhaitez (en fournissant ThreadFactory).
  • Exceptions d'exécution lancées dans TimerTaskkills qu'un fil, ce qui rend Timermort :-( ... à savoir les tâches planifiées ne fonctionneront plus. ScheduledThreadExecutorNon seulement les captures exceptions en mode Process, mais il vous permet de les manipuler si vous voulez (en remplaçant la afterExecuteméthode à partir ThreadPoolExecutor). Tâche qui Cette exception sera annulée, mais d'autres tâches continueront de s'exécuter.

Si vous pouvez utiliser à la ScheduledThreadExecutorplace de Timer, faites-le.

EncoreScheduledThreadExecutor une chose ... bien qu'il 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 a la ScheduledThreadExecutorclasse.

Peter Štibraný
la source
63

S'il est à votre disposition, il est difficile de penser à une raison pour ne pas utiliser le framework exécuteur Java 5. Appel:

ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();

vous donnera un ScheduledExecutorServiceavec des fonctionnalités similaires à Timer(c'est- à -dire qu'il sera monothread) mais dont l'accès peut être légèrement plus évolutif (sous le capot, il utilise des structures simultanées plutôt qu'une synchronisation complète comme avec la Timerclasse). L'utilisation d'un ScheduledExecutorServiceoffre également des avantages tels que:

  • Vous pouvez le personnaliser si besoin est (voir le newScheduledThreadPoolExecutor()ou le ScheduledThreadPoolExecutorcours)
  • Les exécutions ponctuelles peuvent renvoyer des résultats

Les seules raisons pour lesquelles Timerje pense 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)
Neil Coffey
la source
1
Une autre raison de l'utilisation TimerTaskpeut être la disponibilité d'une scheduledExecutionTime()méthode qui ne semble pas avoir d'équivalent ScheduledExecutorService.
Rohit Agarwal
3
Autre remarque: j'écris ce commentaire en 2k17, il n'y a plus de J2ME. il est déjà mort.
msangel
1
La classe Java Timer est merdique.
JohnyTex
26

ExecutorService est plus récent et plus général. Une minuterie n'est qu'un fil qui exécute périodiquement des éléments que vous avez planifiés pour elle.

Un ExecutorService peut être un pool de threads, ou même réparti sur d'autres systèmes dans un cluster et faire des choses comme une exécution par lots ponctuelle, etc.

Il suffit de regarder ce que chacun propose pour décider.

Dustin
la source
16

Voici quelques bonnes pratiques supplémentaires concernant l'utilisation de la minuterie:

http://tech.puredanger.com/2008/09/22/timer-rules/

En général, j'utiliserais Timer pour des trucs rapides et sales et Executor pour une utilisation plus robuste.

Alex Miller
la source
8

Depuis la page de documentation Oracle sur ScheduledThreadPoolExecutor

Un ThreadPoolExecutor qui peut en outre planifier des commandes à exécuter après un certain délai ou à exécuter 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 (que cette classe étend) sont requises.

ExecutorService/ThreadPoolExecutorou ScheduledThreadPoolExecutorest un choix évident lorsque vous avez plusieurs threads de travail.

Pour de ExecutorServiceplusTimer

  1. Timerne peut pas tirer parti des cœurs de processeur disponibles contrairement à en ExecutorServiceparticulier avec plusieurs tâches utilisant des saveurs ExecutorServicecomme ForkJoinPool
  2. ExecutorServicefournit une API collaborative si vous avez besoin d'une coordination entre plusieurs tâches. Supposons que vous devez soumettre N nombre de tâches de travail et attendre la fin de chacune d'entre elles. Vous pouvez facilement y parvenir avec invokeAll API. Si vous voulez obtenir le même résultat avec plusieurs Timertâches, ce ne serait pas simple.
  3. ThreadPoolExecutor fournit une meilleure API pour la gestion du cycle de vie des threads.

    Les pools de threads résolvent deux problèmes différents: ils fournissent 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 fournissent un moyen de limiter et de gérer les ressources, y compris les threads, consommées lors de l'exécution d'une collection de Tâches. Chaque ThreadPoolExecutor conserve é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 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

    ré. Fournit un meilleur mécanisme de gestion des exceptions

Ravindra babu
la source
5

La raison pour laquelle je préfère parfois Timer à Executors.newSingleThreadScheduledExecutor () est que j'obtiens un code beaucoup plus propre lorsque j'ai besoin que le timer s'exécute sur les threads du 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.

Siamaster
la source