18

Mi fragmento de código:¿En qué casos Future.get() ExecutionException tiro o InterruptedException

ExecutorService executor = Executors.newSingleThreadExecutor(); 
try { 
    Task t = new Task(response,inputToPass,pTypes,unit.getInstance(),methodName,unit.getUnitKey()); 
    Future<SCCallOutResponse> fut = executor.submit(t); 
    response = fut.get(unit.getTimeOut(),TimeUnit.MILLISECONDS); 
} catch (TimeoutException e) { 
    // if the task is still running, a TimeOutException will occur while fut.get() 
    cat.error("Unit " + unit.getUnitKey() + " Timed Out"); 
    response.setVote(SCCallOutConsts.TIMEOUT); 
} catch (InterruptedException e) { 
    cat.error(e); 
} catch (ExecutionException e) { 
    cat.error(e); 
} finally { 
    executor.shutdown(); 
} 

¿Cómo debo manejar la InterruptedException y ExecutionException en el código?

¿Y en qué casos, se lanzan estas excepciones?

Respuesta

27

ExecutionException e InterruptedException son dos cosas muy diferentes.

ExecutionException envuelve cualquier excepción que el hilo que se está ejecutando lanzó, por lo que si su hilo estaba haciendo algún tipo de IO que causara una IOException, eso sería envuelto en ExecutionException y rethrown.

Una interruptedException no es un signo de que algo haya salido mal. Está ahí para darte una forma de que tus hilos sepan cuándo es momento de parar para que puedan terminar su trabajo actual y salir con gracia. Digamos que quiero que mi aplicación deje de ejecutarse, pero no quiero que mis hilos cuelguen lo que están haciendo en medio de algo (que es lo que pasaría si los convirtiera en hilos de daemon). Así que cuando la aplicación se está cerrando, mi código llama al método de interrupción en estos hilos, que establece el indicador de interrupción en ellos, y la próxima vez que esos hilos están esperando o durmiendo, comprueban el indicador de interrupción y lanzan una InterruptedException, que puedo usar para salir de la lógica de procesamiento/bucle infinito en la que están involucrados los hilos. (Y si el hilo no espera ni duerme, puede verificar el indicador de interrupción periódicamente). Entonces es una instancia de una excepción que se usa para cambiar el flujo de la lógica La única razón por la que debe iniciar sesión es en un programa de ejemplo para mostrarle lo que está sucediendo, o si está depurando un problema donde la lógica de interrupción no funciona correctamente.

+0

Hay una manera de evitar que ExecutionException arroje, cuando hay una excepción en el procesamiento de una tarea. Incluso si capturó la Excepción arroja el procesamiento y lo maneja, todavía ajusta la excepción a ExecutionException y lo arroja al get. –

+0

Existe una relación entre InterruptedException y ExecutionException, solo para saber cuál capturar primero. En la pregunta de SO capta la excepción InterruptedException primero y luego la ExecutionException. ¿El comportamiento será el mismo si cambiamos el orden? – prime

+0

@prime: ver https://stackoverflow.com/a/10964899/217324. Ambas excepciones se extienden Excepción, ninguna es más específica que la otra. El orden no importa en este caso. –

6

InterruptedException se lanzará si se llama al interrupt en el hilo de espera antes de que se complete el cálculo.

ExecutionException se lanzarán si el cálculo involucrado (Task en este caso) arroja una excepción.

La forma en que desee manejar esto dependerá por completo de su aplicación.

EDIT: He aquí una demostración de ser interrumpido:

import java.util.concurrent.*; 

public class Test 
{ 
    public static void main(String[] args) throws Exception 
    { 
     ExecutorService executor = Executors.newFixedThreadPool(2); 
     Future<String> future = executor.submit(new SlowCallable()); 
     executor.submit(new Interruptor(Thread.currentThread())); 
     try 
     { 
      System.out.println(future.get()); 
     } 
     catch (InterruptedException e) 
     { 
      System.out.println("I was interrupted"); 
     } 
    } 

    private static class Interruptor implements Callable<String> 
    { 
     private final Thread threadToInterrupt; 

     Interruptor(Thread threadToInterrupt) 
     { 
      this.threadToInterrupt = threadToInterrupt; 
     } 

     public String call() throws Exception 
     { 
      Thread.sleep(2000); 
      threadToInterrupt.interrupt(); 
      return "interrupted other thread"; 
     } 
    } 

    private static class SlowCallable implements Callable<String> 
    { 
     public String call() throws Exception 
     { 
      Thread.sleep(5000); 
      return "finished"; 
     } 
    } 
} 
+0

si llamo a Thread.interrupt(), el indicador de interrupción se establece en verdadero. Pero InterruptedException no se arroja –

+0

No tiene que ser una excepción no verificada. 'Callable.call()' puede arrojar cualquier cosa. – finnw

+0

@finnw: Absolutamente correcto. Lamento haberme perdido eso –

-1

Código de ejemplo para devolver tres tipos de excepciones.

import java.util.concurrent.*; 
import java.util.*; 

public class ExceptionDemo{ 
    public static void main(String args[]){ 
     int poolSize=1; 
     int maxPoolSize=1; 
     int queueSize=30; 
     long aliveTive=60; 
     ArrayBlockingQueue<Runnable> queue= new ArrayBlockingQueue<Runnable>(queueSize); 
     ThreadPoolExecutor executor= new ThreadPoolExecutor(poolSize,maxPoolSize,aliveTive, 
         TimeUnit.MILLISECONDS,queue); 
     List<Future> futures = new ArrayList<Future>(); 
     for (int i=0; i < 5; i++){ 
      futures.add(executor.submit(new RunnableEx())); 
     } 
     for (Iterator it = futures.iterator(); it.hasNext();){ 
      try { 
       Future f = (Future)it.next(); 
       f.get(4000,TimeUnit.MILLISECONDS); 
      }catch(TimeoutException terr){ 
       System.out.println("Timeout exception"); 
       terr.printStackTrace(); 
      } 
      catch(InterruptedException ierr){ 
       System.out.println("Interrupted exception:"); 
       ierr.printStackTrace(); 
      }catch(ExecutionException err){ 
       System.out.println("Exeuction exception:"); 
       err.printStackTrace(); 
       Thread.currentThread().interrupt(); 
      } 
     } 
     executor.shutdown(); 
    } 
} 

class RunnableEx implements Runnable{ 
    public void run() { 
     // code in here 
     System.out.println("Thread name:"+Thread.currentThread().getName()); 
     try{ 
      Random r = new Random(); 
      if (r.nextInt(2) == 1){ 
       Thread.sleep(2000); 
      }else{ 
       Thread.sleep(4000); 
      } 
      System.out.println("eee:"+1/0); 
     }catch(InterruptedException irr){ 
      irr.printStackTrace(); 
     } 
    } 
} 

de salida:

Thread name:pool-1-thread-1 
Timeout exception 
Thread name:pool-1-thread-1 
java.util.concurrent.TimeoutException 
     at java.util.concurrent.FutureTask.get(FutureTask.java:201) 
     at ExceptionDemo.main(ExceptionDemo.java:20) 
Thread name:pool-1-thread-1 
Exeuction exception: 
java.util.concurrent.ExecutionException: java.lang.ArithmeticException:/by zero 
     at java.util.concurrent.FutureTask.report(FutureTask.java:122) 
     at java.util.concurrent.FutureTask.get(FutureTask.java:202) 
     at ExceptionDemo.main(ExceptionDemo.java:20) 
Caused by: java.lang.ArithmeticException:/by zero 
     at RunnableEx.run(ExceptionDemo.java:49) 
     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) 
     at java.util.concurrent.FutureTask.run(FutureTask.java:262) 
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
     at java.lang.Thread.run(Thread.java:744) 
Interrupted exception: 
java.lang.InterruptedException 
     at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:400) 
     at java.util.concurrent.FutureTask.get(FutureTask.java:199) 
     at ExceptionDemo.main(ExceptionDemo.java:20) 
Timeout exception 
java.util.concurrent.TimeoutException 
     at java.util.concurrent.FutureTask.get(FutureTask.java:201) 
Thread name:pool-1-thread-1 
     at ExceptionDemo.main(ExceptionDemo.java:20) 
Thread name:pool-1-thread-1 
Timeout exception 
java.util.concurrent.TimeoutException 
     at java.util.concurrent.FutureTask.get(FutureTask.java:201) 
     at ExceptionDemo.main(ExceptionDemo.java:20) 

TimeoutException: Excepción lanzada cuando un bloqueo de los tiempos de operación a cabo.

En el ejemplo anterior, algunas tareas están tomando más tiempo (debido a 4 segundos del sueño) y bloqueando el funcionamiento de get() en Future

Cualquiera de aumentar el tiempo de espera u optimizar tarea Ejecutable.

ExecutionException: excepción lanzada al intentar recuperar el resultado de una tarea que abortada por lanzar una excepción => El cálculo produjo una excepción

En el ejemplo anterior, esta Exception se simula a través de ArithmeticException:/by zero

Generalmente, deberías atraparlo, corrige la causa raíz si es trivial, como se cita en el ejemplo.

InterruptedException: Lanzado cuando un hilo está esperando, durmiendo u ocupado de otra manera, y el hilo se interrumpe, ya sea antes o durante la actividad.

En el ejemplo anterior, este Exception se simula al interrumpir el hilo actual durante ExecutionException.

En general, debe atraparlo no actuar en consecuencia.

+0

@downvoter, vuelva a verificar la pregunta y la respuesta. Los motivos de la documentación oficial de Java se citan aquí. –

+0

Existe una relación entre InterruptedException y ExecutionException, solo para saber cuál capturar primero. En la pregunta de SO capta la excepción InterruptedException primero y luego la ExecutionException. ¿El comportamiento será el mismo si cambiamos el orden? – prime

+0

InterruuptedException debe detectarse primero –

Cuestiones relacionadas