2009-08-15 5 views
7

En el siguiente código, estoy atrapando una TimeoutException después de 100 segundos como estaba previsto. En este punto, esperaría que el código salga de main y que el programa finalice, pero sigue imprimiéndose en la consola. ¿Cómo hago para que la tarea deje de ejecutarse después del tiempo de espera?¿Cómo consigo que FutureTask regrese después de TimeoutException?

private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool(); 

private static <T> T timedCall(Callable<T> c, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException { 
    FutureTask<T> task = new FutureTask<T>(c); 
    THREAD_POOL.execute(task); 
    return task.get(timeout, timeUnit); 
} 


public static void main(String[] args) { 

    try { 
     int returnCode = timedCall(new Callable<Integer>() { 
      public Integer call() throws Exception { 
       for (int i=0; i < 1000000; i++) { 
        System.out.println(new java.util.Date()); 
        Thread.sleep(1000); 
       } 
       return 0; 
      } 
     }, 100, TimeUnit.SECONDS); 
    } catch (Exception e) { 
     e.printStackTrace(); 
     return; 
    } 


} 

Respuesta

8

Usted necesita cancelar su tarea en tiempo de espera (e interrumpir su rosca). Para eso está el método cancel(true). :

private static final ExecutorService THREAD_POOL = Executors.newCachedThreadPool(); 

private static <T> T timedCall(FutureTask<T> task, long timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException { 
    THREAD_POOL.execute(task); 
    return task.get(timeout, timeUnit); 
} 


public static void main(String[] args) { 
     try { 
      FutureTask<Integer> task = new FutureTask<Integer>(new Callable<Integer>() { 
       public Integer call() throws Exception { 
         for (int i=0; i < 1000000; i++) { 
           if (Thread.interrupted()) return 1; 
           System.out.println(new java.util.Date()); 
           Thread.sleep(1000); 
         } 
         return 0; 
       } 
      }); 
      int returnCode = timedCall(task, 100, TimeUnit.SECONDS); 
     } catch (Exception e) { 
       e.printStackTrace(); 
       task.cancel(true); 
     } 
     return; 
} 
+1

! Task.cancelled() debería ser! IsCancelled() como djna escribió originalmente – Zed

+1

Creo que es mucho mejor usar interrupciones. En primer lugar, su código invocable no necesita saber nada acerca de 'task'. Segundo, cuando usa varias operaciones de bloqueo en su código invocable (como 'Thread.sleep()'), estas no reaccionarán a task.isCancelled(), pero generalmente reaccionan a interrupciones. Entonces, usar 'cancel (true)' y hacer que tu código sea consciente de las interrupciones suele ser la mejor manera de hacerlo. (Su código también será más general, porque el mecanismo de interrupciones es ampliamente utilizado en Java) –

+0

Creo que mi punto es que "La interrupción es un mecanismo cooperativo". (http://www.ibm.com/developerworks/java/library/j-jtp05236.html) –

1

Una vez que captó la TimeoutException, es necesario llamar al método cancel (verdadero) de su tarea ...

o apagar el ExecutorService llamando shutdownNow() ...

o salir de la máquina virtual llamando System.exit (0)

en función de sus necesidades

4

Su llamador debe poder detenerse rápidamente, cuando sea necesario.

Su código:

public Integer call() throws Exception { 
    for (int i=0; i < 1000000 && !task.cancelled(); i++) { 
     System.out.println(new java.util.Date()); 
     Thread.sleep(1000); // throws InterruptedException when thread is interrupted 
    } 
    return 0; 
} 

ya es capaz de hacer eso gracias a llamar Thread.sleep(). El punto es que futureTask.cancel(true) interrumpirá otro hilo, y su código debe reaccionar a esta interrupción. Thread.sleep() hace eso. Si no usó Thread.sleep() u otro código de bloqueo interrumpible, deberá marcar Thread.currentThread().isInterrupted() por su cuenta y salir lo antes posible (por ejemplo, lanzando new InterruptedException()) cuando considere que esto es cierto.

Debe llamar al futureTask.cancel(true); desde su manejador de excepciones para cancelar e interrumpir el hilo que ejecuta su tarea.

Mi consejo es aprender sobre el mecanismo de interrupción (este es el gran artículo: Dealing with InterruptedException), y úselo.

Cuestiones relacionadas