2009-07-24 7 views
6

Je commence juste à regarder dans Futures et le ScheduledExecutorService dans Java, et je me demande pourquoi mon Callable ne fonctionne pas sur l'horaire que j'ai indiqué. Dans cet exemple de code, l'appelable s'exécute une fois, mais l'application ne se termine jamais, et la tâche ne s'exécute plus, ce qui est ce que je m'attendais à arriver (je suis sûr que le problème est avec mes attentes).À la recherche de la clarté sur Java ScheduledExecutorService et FutureTask

Les exécutions fonctionnent correctement; Les callables semblent bloquer pour toujours, mais je ne sais pas pourquoi ... Qu'est-ce qui me manque?

Merci!

public class ExecutorExample { 

    /** 
    * @param args 
    * @throws ExecutionException 
    * @throws InterruptedException 
    */ 
    public static void main(String[] args) throws InterruptedException, ExecutionException { 

     ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(5); 

     FutureTask<ArrayList<String>> ft1 = new FutureTask<ArrayList<String>>(new Callable<ArrayList<String>>(){ 
      @Override 
      public ArrayList<String> call() { 
       ArrayList<String> stuff = new ArrayList<String>(); 
       for(int i = 0;i<10;i++){ 
        String thing ="Adding " + i + " to result"; 
        stuff.add(thing); 
        System.out.println(thing); 

       } 
       return stuff; 
      }}); 

     scheduler.scheduleAtFixedRate(ft1, 0, 1, TimeUnit.SECONDS); 

     System.out.println(ft1.get()); 
     System.out.println(ft1.isDone()); 

    } 
} 

Répondre

8

Le problème est que FutureTask est utilisé, et que la documentation de classe dit: « Une fois le calcul terminé, le calcul ne peut pas être redémarrés ou annulé. »

Après la méthode run de FutureTask a été invoqué une fois, les invocations ultérieures reviennent immédiatement, sans déléguer à Callable instance de la tâche.

Seul un Runnable peut être utilisé comme tâche récurrente, ce qui ne permet pas de renvoyer un résultat. Au lieu de cela, attribuez à la tâche Runnable un rappel qu'elle peut invoquer à la fin de sa méthode run, pour rapporter les résultats de chaque exécution de la tâche aux écouteurs d'autres threads.

+1

Je ne suis pas sûr de suivre cela. FutureTask implémente Runnable, et je m'attendrais à ce qu'il appelle la méthode call(), et stocke le résultat. Je m'attendrais alors à ce que get() bloque jusqu'à ce que le travail soit fini, ou renvoie le résultat caché immédiatement. Donc, le planificateur n'exécuterait-il pas FutureTask, ce qui entraînerait call() et le résultat serait mis en cache pour une collecte ultérieure? –

+1

Oui, mais seulement une fois. Toutes les invocations planifiées après la première appelaient 'run' sur la FutureTask, mais cette méthode d'exécution« court-circuite »sans invoquer' call' sur Callable. Mais le planificateur n'est pas conscient de cela et continue de fonctionner pour appeler la FutureTask, de sorte que le programme ne se termine pas. – erickson

+0

Cela prend tout son sens. J'étais tellement tête baissée dans les javadocs pour les Executors et ses semblables et j'ai complètement raté cette ligne évidente dans FutureTask. Comme une question suivante, si ce que je veux arriver à la suite de ma tâche est qu'un BlockingQueue est mis à jour, est-il préférable de simplement passer cette file dans chaque runnable, ou d'implémenter un écouteur qui vivrait en dehors du runnable qui manipule ensuite la file d'attente en fonction des résultats? Merci encore –

Questions connexes