Timer & TimerTask versus Thread + Sleep en Java

102

J'ai trouvé des questions similaires posées ici mais il n'y avait pas de réponses à ma satisfaction. Donc reformuler la question à nouveau -

J'ai une tâche qui doit être effectuée périodiquement (disons 1 minute d'intervalle). Quel est l'avantage d'utiliser Timertask & Timer pour ce faire par rapport à la création d'un nouveau thread qui a une boucle infinie avec sommeil?

Extrait de code utilisant timertask-

TimerTask uploadCheckerTimerTask = new TimerTask(){

 public void run() {
  NewUploadServer.getInstance().checkAndUploadFiles();
 }
};

Timer uploadCheckerTimer = new Timer(true);
uploadCheckerTimer.scheduleAtFixedRate(uploadCheckerTimerTask, 0, 60 * 1000);

Extrait de code utilisant Thread et sleep-

Thread t = new Thread(){
 public void run() {
  while(true) {
   NewUploadServer.getInstance().checkAndUploadFiles();
   Thread.sleep(60 * 1000);
  }
 }
};
t.start();

Je n'ai vraiment pas à m'inquiéter si je rate certains cycles si l'exécution de la logique prend plus que l'intervalle de temps.

Veuillez commenter ceci.

Mise à jour:
Récemment, j'ai trouvé une autre différence entre l'utilisation de Timer et Thread.sleep (). Supposons que l'heure système actuelle soit 11h00. Si nous annulons l'heure système à 10h00 pour une raison quelconque, The Timer arrêtera d'exécuter la tâche jusqu'à ce qu'elle atteigne 11h00, tandis que la méthode Thread.sleep () continuerait d'exécuter la tâche sans entrave. Cela peut être un décideur majeur pour décider quoi utiliser entre les deux.

Keshav
la source
21
Point d'ordre: Timer et TimerTask sont obsolètes et ont effectivement été remplacés par ExecutorService, bien que votre argument soit toujours valable.
skaffman
Merci pour la pointe, j'ai décidé d'utiliser ExecutorService :)
Keshav
Merci à tous pour les réponses, m'a sûrement donné plus de compréhension!
Keshav
6
Le minuteur n'est pas obsolète et est préférable lorsqu'un seul thread est nécessaire. ( java.sun.com/javase/6/docs/api/java/util/Timer.html )
Justin
2
Timer et TimerTask sont toujours utiles dans les environnements JME où ExecutorService n'existe pas (depuis JME Java 1.3 basé ...).
ス ー パ ー フ ァ ミ コ ン

Réponses:

67

L'avantage de TimerTask est qu'il exprime beaucoup mieux votre intention (c'est-à-dire la lisibilité du code), et il a déjà implémenté la fonction cancel ().

Notez qu'il peut être rédigé dans une forme plus courte ainsi que votre propre exemple:

Timer uploadCheckerTimer = new Timer(true);
uploadCheckerTimer.scheduleAtFixedRate(
    new TimerTask() {
      public void run() { NewUploadServer.getInstance().checkAndUploadFiles(); }
    }, 0, 60 * 1000);
Zed
la source
si la minuterie est utilisée pour tous les jours, à 2 heures précises 21h et 9h, ... comment donner les valeurs? sur le code ci-dessus ... @Zed?
gumuruh
12

Timer / TimerTask prend également en compte le temps d'exécution de votre tâche, ce sera donc un peu plus précis. Et il traite mieux les problèmes de multithreading (comme éviter les blocages, etc.). Et bien sûr, il est généralement préférable d'utiliser un code standard bien testé au lieu d'une solution maison.

MartinStettner
la source
5

Je ne sais pas pourquoi mais un programme que j'écrivais utilisait Timers et sa taille de tas augmentait constamment, une fois que je l'ai changé en problème Thread / sleep résolu.

Qandeel
la source
9
Le minuteur crée une file d'attente de tâches constamment mise à jour. Lorsque le minuteur est terminé, il se peut qu'il ne soit pas récupéré immédiatement. Ainsi, créer plus de minuteries n'ajoute que plus d'objets sur le tas. Thread.sleep () met uniquement en pause le thread, donc la surcharge de mémoire serait extrêmement faible.
Darryl Gerrow
4

Si votre thread obtient une exception et est tué, c'est un problème. Mais TimerTask s'en chargera. Il fonctionnera indépendamment de l'échec de l'exécution précédente.

Pile Popper
la source
4

De la Timer documentation :

Java 5.0 a introduit le package java.util.concurrent et l'un des utilitaires de concurrence qu'il contient est ScheduledThreadPoolExecutor, qui est un pool de threads pour exécuter à plusieurs reprises des tâches à un rythme ou un délai donné. C'est effectivement un remplacement plus polyvalent pour la combinaison Timer / TimerTask, car il autorise plusieurs threads de service, accepte diverses unités de temps et ne nécessite pas de sous-classement TimerTask (implémentez simplement Runnable). La configuration de ScheduledThreadPoolExecutor avec un thread le rend équivalent à Timer.

Alors préférez ScheduledThreadExecutorau lieu de Timer:

  • Timerutilise un thread d'arrière-plan unique qui est utilisé pour exécuter toutes les tâches du minuteur, séquentiellement. Les tâches doivent donc se terminer rapidement, sinon cela retardera l'exécution des tâches suivantes. Mais dans ce cas, ScheduledThreadPoolExecutornous pouvons configurer n'importe quel nombre de threads et pouvons également avoir un contrôle total en fournissant ThreadFactory.
  • Timerpeut être sensible à l'horloge système car il utilise la Object.wait(long)méthode. Mais ScheduledThreadPoolExecutornon.
  • Les exceptions d'exécution lancées dans TimerTask tueront ce thread particulier, rendant ainsi Timer mort là où nous pouvons gérer cela ScheduledThreadPoolExecutorafin que les autres tâches ne soient pas affectées.
  • Timerfournit une cancelméthode pour terminer le minuteur et ignorer toutes les tâches planifiées, mais il n'interfère pas avec la tâche en cours d'exécution et ne la laisse pas se terminer. Mais si le minuteur fonctionne en tant que thread démon, que nous l'annulions ou non, il se terminera dès que tous les threads utilisateur auront fini de s'exécuter.

Minuterie vs Thread.sleep

Timer utilise Object.waitet il est différent deThread.sleep

  1. Un waitthread en attente ( ) peut être notifié (en utilisant notify) par un autre thread mais un thread en veille ne peut pas l'être, il ne peut être interrompu.
  2. Une attente (et une notification) doit se produire dans un bloc synchronisé sur l'objet moniteur, contrairement à la mise en veille.
  3. Pendant que le sommeil ne libère pas le verrou, l'attente libère le verrou pour que l'objet wait soit appelé.
akhil_mittal
la source
informations très utiles, De plus, l'utilisation de Thread.sleep dans une boucle infinie peut entraîner une utilisation élevée du processeur dans de faibles délais.
Amir Fo
3

Il y a un argument crucial contre la gestion de cette tâche à l'aide de threads et de sleepméthodes Java . Vous utilisez while(true)pour rester indéfiniment dans la boucle et mettre en veille le thread en le mettant en veille. Que faire si NewUploadServer.getInstance().checkAndUploadFiles();prend certaines ressources synchronisées. Les autres threads ne pourront pas accéder à ces ressources, une famine peut survenir, ce qui peut ralentir toute votre application. Ces types d'erreurs sont difficiles à diagnostiquer et c'est une bonne idée de prévenir leur existence.

L'autre approche déclenche l'exécution du code qui vous tient à cœur, c'est NewUploadServer.getInstance().checkAndUploadFiles();à dire en appelant la run()méthode de votre TimerTasktout en laissant d'autres threads utiliser les ressources entre-temps.

Boris Pavlović
la source
16
Je ne comprends pas cet argument. Les deux choix lancent la même méthode à partir d'un thread, les deux choix dorment dans un thread pendant qu'ils attendent d'être exécutés. Il n'y aura aucune différence de famine entre les deux choix.
satur9nine
2

Je pense que je comprends votre problème, je vois quelque chose de très similaire. J'ai des minuteries qui sont récurrentes, certaines toutes les 30 minutes et d'autres tous les deux jours. D'après ce que j'ai lu et les commentaires que je vois, il semble que le ramasse-miettes ne fonctionnera jamais car toutes les tâches ne sont jamais terminées. Je pense que le ramasse-miettes s'exécuterait quand un minuteur est en veille, mais je ne le vois pas et selon la documentation, il ne le fait pas.

Je pense que la création de nouveaux threads se termine et permet le ramassage des ordures.

Quelqu'un s'il vous plaît me prouver le contraire, réécrire ce que j'ai hérité va être une douleur.

Ken
la source