2010-07-07 9 views
6

¿Por qué el scheduleWithFixedDelay de Java funciona con un Runnable pero no un FutureTask envolviendo un ejecutable?¿Por qué el scheduleWithFixedDelay de Java funciona con un Runnable pero no un FutureTask <?> que envuelve un elemento ejecutable?

Esto se puede demostrar muy fácilmente con dos diferentes ejemplos de código:

ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); 
     executorService.scheduleWithFixedDelay(new FutureTask<Integer>(new Callable<Integer>() { 

      @Override 
      public Integer call() throws Exception { 
       System.out.println("beep"); 
       return 1; 
      } 
     }), 1, 5, TimeUnit.SECONDS); 

produce:

pitido

Pero la aplicación no sale, simplemente parece que esperar .

pero:

ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); 
    executorService.scheduleWithFixedDelay(new Runnable() { 

     @Override 
     public void run() { 
      System.out.println("beep "); 
     } 
    }, 1, 5, TimeUnit.SECONDS); 

produce:

pitido pitido pitido pitido pitido

en intervalos de 5 segundos.

Parece que hay algún tipo de bloqueo aquí que no puedo determinar.

+0

Cada vez que ejecuto el código que produce el beep beep beep beep beep, ni siquiera recibo un bip, y el proceso finaliza incluso antes de la ejecución. Si cambio el retraso inicial de 1 a 0, obtengo un pitido. – Marcus

+0

No importa, eso era porque necesitaba un ejecutorService.awaitTermination() para bloquear hasta que finalizara. – Marcus

Respuesta

13

Porque estás abusando un poco de FutureTask.

Un FutureTask es "un cálculo asincrónico cancelable" de acuerdo con los Javadocs, pero más coloquialmente envuelve una ejecución particular de Runnable/Callable para proporcionar la asincronía. En realidad, no me di cuenta de que implementó Runnable hasta que lo comprobé hace un momento: la implementación de run() "establece este futuro en el resultado de su cálculo".

Entonces, lo que está sucediendo en su primer ejemplo es que está programando la tarea futura, su método de ejecución se llama después de 1 segundo y calcula el resultado del cálculo (es decir, ejecuta el Runnable incrustado). Cuando este método finaliza, FutureTask se ha ejecutado y tiene su resultado concreto, por lo que las invocaciones futuras de run() no son operaciones.

Creo que el problema de raíz aquí es que no parece tener sentido programar un FutureTask directamente, al menos no de la manera en que lo hace aquí. Si desea que se ejecute un poco de código cada cinco segundos, entonces definitivamente debe tomar el segundo enfoque. The FutureTask incorpora un cálculo (¡único!); no hay ninguna razón por la que desee que se invoque varias veces y, de hecho, está almacenando en caché específicamente el resultado para evitar esto.

+1

Esa es una excelente respuesta gracias, estaba usando un FutureTask con un ejecutable dentro en este ejemplo, pero el caso de negocios, era que estaba intentando introducir unllamable en el programador, y el FutureTask podría tomar un argumento invocable, y satisfacer la interfaz ejecutable. –

3

No se supone que pasar FutureTask objetos en un ScheduledExecutorService, se supone que pasar en Runnable o Callable, que luego se vuelve un FutureTask. El hecho de que FutureTask implemente la interfaz Runnable parece ser una falla de diseño desafortunada, lo que le permite volver a ingresar la salida como entrada.

En cuanto a por qué obtienes este comportamiento, es posiblemente una interacción extraña entre los componentes, y probablemente indefinida.

Cuestiones relacionadas