web-dev-qa-db-fra.com

Timer et TimerTask vs Thread + dormir en Java

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

J'ai une tâche à faire périodiquement (par exemple, toutes les minutes). Quel avantage y a-t-il à utiliser Timertask & Timer pour le faire, par opposition à la création d'un nouveau thread ayant 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 manque certains cycles si l'exécution de la logique prend plus que l'intervalle de temps.

S'il vous plaît commenter sur ce ..

Mettre à jour:
Récemment, j'ai trouvé une autre différence entre utiliser Timer et Thread.sleep (). Supposons que l'heure actuelle du système est 11h00. Si nous rétrogradons l'heure système à 10h00 pour une raison quelconque, le minuteur arrêtera l'exécution de la tâche jusqu'à 11h00, alors que la méthode Thread.sleep () continuerait à exécuter la tâche sans entrave. Cela peut être un décideur majeur pour décider quoi utiliser entre ces deux.

101
Keshav

L’avantage de TimerTask est qu’il exprime beaucoup mieux votre intention (lisibilité du code) et qu’il dispose déjà de la fonction cancel ().

Notez qu'il peut être écrit sous 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);
65
Zed

Timer/TimerTask prend également en compte le temps d'exécution de votre tâche, elle sera donc un peu plus précise. 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.

13
MartinStettner

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 Thread/problème de sommeil résolu.

5
Qandeel

Si vous thread obtenez une exception et est tué, c'est un problème ... mais TimerTask s'en occupera. Il fonctionnera indépendamment de l'échec de l'exécution précédente.

4
Stack Popper

Il existe un argument crucial contre la gestion de cette tâche à l'aide de threads Java et de la méthode sleep. Vous utilisez while(true) pour rester indéfiniment dans la boucle et hiberner le thread en le mettant en veille. Et si NewUploadServer.getInstance().checkAndUploadFiles(); utilise des ressources synchronisées. D'autres threads ne pourront pas accéder à ces ressources, la famine peut survenir, ce qui peut ralentir l'ensemble de votre application. Ces types d’erreurs sont difficiles à diagnostiquer et c’est une bonne idée d’empêcher leur existence.

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

3
Boris Pavlović

De la Timerdocumentation :

Java 5.0 a introduit le package Java.util.concurrent et l’un des fichiers les utilitaires de simultanéité qui y figurent est le ScheduledThreadPoolExecutor qui est un pool de threads pour l'exécution répétée de tâches à un taux donné ou retard. C'est effectivement un remplacement plus polyvalent pour le Combinaison Timer/TimerTask, car elle permet plusieurs threads de service, accepte différentes unités de temps et ne nécessite pas de sous-classe TimerTask (implémentez simplement Runnable). Configuration de ScheduledThreadPoolExecutor avec un fil le rend équivalent à Timer.

Alors, préférez ScheduledThreadExecutor au lieu de Timer:

  • Timer utilise un seul thread d'arrière-plan utilisé pour exécuter de manière séquentielle toutes les tâches du minuteur. Les tâches doivent donc se terminer rapidement, sinon cela retardera l'exécution des tâches suivantes. Mais dans le cas de ScheduledThreadPoolExecutor, nous pouvons configurer un nombre illimité de threads et également avoir le contrôle total en fournissant ThreadFactory.
  • Timer peut être sensible à l'horloge système car il utilise la méthode Object.wait(long). Mais ScheduledThreadPoolExecutor n'est pas.
  • Les exceptions d'exécution lancées dans TimerTask vont tuer ce fil particulier, rendant ainsi Timer mort, car nous pouvons gérer cela dans ScheduledThreadPoolExecutor, de sorte que les autres tâches ne soient pas impactées.
  • Timer fournit la méthode cancel pour mettre fin au chronomètre et supprimer toutes les tâches planifiées. Toutefois, elle n’interfère pas avec la tâche en cours d’exécution et la laisse se terminer. Mais si timer est exécuté en tant que thread de démon, qu'il soit annulé ou non, il se terminera dès que tous les threads de l'utilisateur auront fini de s'exécuter.

Minuterie vs Thread.sleep

Le minuteur utilise Object.wait et est différent de Thread.sleep

  1. Un thread en attente (wait) peut être notifié (à l'aide de notify) par un autre thread, mais un en veille ne peut l'être, il ne peut être interrompu.
  2. Une attente (et une notification) doit se produire dans un bloc synchronisé sur l'objet de surveillance, contrairement à la mise en veille.
  3. Pendant le sommeil, le verrou n'est pas libéré, l'attente libère le verrou pour que l'objet soit appelé.
1
i_am_zero

Je pense que je comprends votre problème, je vois quelque chose de très similaire. J'ai des minuteries qui se répètent, 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 la récupération de place ne s'exécutera jamais car toutes les tâches ne sont jamais terminées. Je pense que la collecte des ordures s’exécute quand une minuterie est en veille, mais je ne la vois pas et, d’après la documentation, elle ne la voit pas.

Je pense que la création de nouveaux threads se termine et autorise la récupération de place.

Quelqu'un s'il te plaît prouve-moi que j'ai tort, réécrire ce que j'ai hérité va être une douleur.

1
Ken