2 votes

Java scheduleAtFixedRate + Thread.sleep

Je ne fais qu'explorer la méthode scheduleAtFixedRate de la classe ScheduledExecutorService en Java.

Voici mon code suspect :

ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);

  Runnable command = () -> {
    System.out.println("Yo");
    try {
      Thread.sleep(4000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  };

  scheduledExecutorService.scheduleAtFixedRate(command, 0, 1, TimeUnit.SECONDS);

Je m'attendais à ce que, toutes les 1 seconde, scheduledExecutorService essaie de prendre un nouveau thread dans le pool et de le démarrer.

L'API dit : "scheduledExecutorService crée et exécute une action périodique qui devient active d'abord après le délai initial donné, et ensuite avec la période donnée. /(supprimé sans importance)/ Si une exécution de cette tâche prend plus de temps que sa période, les exécutions suivantes peuvent commencer en retard, mais ne s'exécuteront pas simultanément."

Résultat : chaque nouveau fil de discussion démarre toutes les 4 secondes.

Donc, les questions :

  1. Quel est le piège - Thread.sleep() arrête-t-il tous les threads ou la nuance dans ce comportement - "Si une exécution de cette tâche prend plus de temps que sa période, les exécutions suivantes peuvent commencer en retard, mais ne s'exécuteront pas simultanément" ?

  2. Si "ne s'exécutera pas simultanément" est vrai dans cette situation - pourquoi avons-nous besoin de ce pool de plusieurs threads si chaque thread démarre après l'exécution du thread précédent ?

  3. Existe-t-il un exemple simple et valide d'utilisation de scheduleAtFixedRate, où un thread démarre alors que le précédent est toujours en cours d'exécution ?

1voto

ardenit Points 3080
  1. La réponse se trouve dans la citation que vous avez fournie. L'exécuteur attend que la tâche se termine avant de lancer à nouveau cette tâche. Il empêche l'exécution simultanée de plusieurs instances d'une même tâche - dans la plupart des cas, ce comportement est nécessaire. Dans votre cas, l'exécuteur lance une tâche, puis attend 1 seconde de délai, puis attend 3 secondes de plus jusqu'à ce que la tâche en cours soit terminée et seulement ensuite relance cette tâche (il ne lance pas nécessairement un nouveau thread, il peut lancer la tâche dans le même thread).

  2. Votre code n'utilise pas du tout le pool de threads - vous pouvez obtenir exactement le même résultat en utilisant l'exécuteur d'un seul thread.

  3. Si vous voulez obtenir ce comportement :

    Je m'attendais à ce que, toutes les secondes, scheduledExecutorService essaie de prendre un nouveau thread du pool et de le démarrer.

    Alors vous pouvez écrire est comme ceci :

    ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
    
    Runnable command = () -> {
        System.out.println("Yo");
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    };
    
    Runnable commandRunner = () -> {
        scheduledExecutorService.schedule(command, 0, TimeUnit.SECONDS);
    }
    
    scheduledExecutorService.scheduleAtFixedRate(commandRunner, 0, 1, TimeUnit.SECONDS);

    (Il est préférable de créer un programme monofilamentaire ScheduledExecutorService qui fonctionne commandRunner et créer un pool de threads basé sur ExecutorService qui est utilisé par commandRunner d'exécuter command )

1voto

Ankur Chrungoo Points 608

Quel est le piège - Thread.sleep() arrête-t-il tous les fils ou nuance-t-il ce comportement ? ce comportement - "Si une exécution de cette tâche prend plus de temps que son période, alors les exécutions suivantes peuvent commencer en retard, mais ne seront pas s'exécuteront pas en même temps" ?

  • Je n'ai pas bien compris ce que vous voulez dire ici. Mais, essentiellement, dans le code que vous avez partagé, Thread.sleep() fait simplement en sorte que l'exécution du thread prenne 4 secondes, ce qui est plus long que la période définie de 1 seconde. Ainsi, les threads suivants ne s'exécuteront pas après 1 seconde, mais seulement après ~4 secondes d'exécution du thread précédent.

Si "ne s'exécutera pas simultanément" est vrai dans cette situation - pourquoi avons-nous besoin de cette phrase ? pourquoi avons-nous besoin de ce pool de plusieurs threads si chaque thread commence après l'exécution du thread précédent ?

  • Il se peut que vous souhaitiez planifier d'autres types de threads (qui effectuent un travail différent) dans le même exécuteur, qui peuvent s'exécuter en parallèle au code que vous avez partagé. Votre code actuel n'a besoin que d'un seul thread dans le pool, puisque vous ne planifiez qu'un seul travail (Runnable).

Existe-t-il un exemple simple et valide d'utilisation de scheduleAtFixedRate ? où un thread démarre alors que le précédent est toujours en cours d'exécution ?

  • Comme indiqué dans la documentation, l'exécution simultanée ne se produira pas pour le travail que vous avez programmé à taux fixe (avec le code actuel).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X