2009-07-24 15 views
6

Estoy empezando a buscar Futures y el ScheduledExecutorService en Java, y me pregunto por qué mi Callable no se está ejecutando en el horario que he indicado. En este código de ejemplo, el invocable se ejecuta una vez, pero la aplicación nunca se completa, ni la tarea se ejecuta nuevamente, que es lo que esperaba que sucediera (estoy seguro de que el problema está con mis expectativas).Buscando Clarity en Java ScheduledExecutorService y FutureTask

Runnables funcionan bien; Los Callables parecen bloquear para siempre, pero no estoy seguro de por qué ... ¿Qué me estoy perdiendo?

Gracias!

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()); 

    } 
} 

Respuesta

8

El problema es que se utiliza FutureTask, y como dice su documentación de la clase, "Una vez que el cálculo se ha completado, el cálculo no se puede reiniciar o cancelados."

Después de invocar el método run de FutureTask una vez, las invocaciones posteriores regresan inmediatamente, sin delegar a la instancia de la tarea Callable.

Solo se puede utilizar un Runnable como una tarea recurrente, y esto no permite la devolución de un resultado. En su lugar, proporcione a la tarea Runnable una devolución de llamada que pueda invocar al final de su método run, para informar los resultados de cada ejecución de la tarea a los oyentes de otros hilos.

+1

No estoy seguro de seguir esto. FutureTask implementa Runnable, y espero que llame al método call() y almacene el resultado. Entonces esperaría que get() bloqueara hasta que se termine el trabajo, o devuelva el resultado en caché inmediatamente. Entonces, ¿el planificador no ejecutaría el FutureTask, lo que daría como resultado que call() y el resultado se guarde en caché para su posterior reunión? –

+1

Sí, pero solo una vez. Cualquier invocación programada después de la primera llamaría a 'ejecutar' en el FutureTask, pero que el método de ejecución "cortocircuitos" sin invocar 'call' en el Callable. Pero el programador no tiene conocimiento de esto y sigue ejecutándose para invocar FutureTask, por lo que el programa no finaliza. – erickson

+0

Tiene perfecto sentido. Estaba tan agachado en los javadocs por los Executors y su tipo y me perdí por completo esa línea obvia en FutureTask. Como una pregunta de seguimiento, si lo que quiero que suceda como resultado de mi tarea es que se actualiza un BlockingQueue, ¿es preferible pasar esa cola a cada ejecutable, o implementar un oyente que viviría fuera del ejecutable que luego manipula la cola en función de los resultados? Gracias de nuevo –

Cuestiones relacionadas