java - ejemplo - ¿En qué casos Future.get() lanza ExecutionException o InterruptedException
java callable (4)
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();
}
}
}
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 : se TimeoutException excepción cuando se agota el tiempo de una operación de bloqueo.
En el ejemplo anterior, algunas tareas toman más tiempo (debido a 4 segundos de suspensión) y bloquean la operación de get()
en Future
Aumente el tiempo de espera o optimice la tarea Ejecutable.
ExecutionException : Excepción lanzada al intentar recuperar el resultado de una tarea que se canceló lanzando una excepción => El cálculo arrojó una excepción
En el ejemplo anterior, esta Exception
se simula a través de ArithmeticException: / by zero
Por lo general, debería atraparlo y corregir la causa raíz si es trivial como se indica en el ejemplo.
InterruptedException : se lanza cuando un hilo está esperando, durmiendo o está ocupado de otra manera, y el hilo se interrumpe, ya sea antes o durante la actividad.
En el ejemplo anterior, esta Exception
se simula interrumpiendo el hilo actual durante ExecutionException
.
En general, deberías atraparlo, no actuar sobre él.
Mi fragmento de código:
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?
El artículo de IBM Developer Works Tratar con InterruptedException tiene algunos consejos sobre cómo manejar InterruptedException
.
ExecutionException y InterruptedException son dos cosas muy diferentes.
ExecutionException envuelve cualquier excepción que el subproceso ejecutado lanzó, por lo tanto, si su subproceso estaba, por ejemplo, haciendo algún tipo de IO que causó que se lanzara una IOException, se envolvería en una ExecutionException y se volvería a producir.
Una excepción interrumpida no es un signo de que algo haya salido mal. Está ahí para darle una manera de que sus hilos sepan cuándo es el momento de detenerse 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 subprocesos abandonen lo que están haciendo en medio de algo (que es lo que sucedería si los hiciera como demonios). Entonces, cuando la aplicación se está cerrando, mi código llama al método de interrupción en estos subprocesos, que establece el indicador de interrupción en ellos, y la próxima vez que esos subprocesos estén esperando o durmiendo, comprueban el indicador de interrupción y lanzan una InterruptedException, que puedo usar para rescatar cualquier lógica de procesamiento / espera de bucle infinito en la que participan los subprocesos. (Y si el subproceso no espera o está inactivo, solo puede verificar el indicador de interrupción periódicamente). Por lo tanto, es una instancia de una excepción que se está utilizando. para cambiar el flujo lógico. La única razón por la que lo registraría es en un programa de ejemplo para mostrarle lo que está sucediendo, o si está depurando un problema en el que la lógica de interrupción no funciona correctamente.
InterruptedException
lanzará InterruptedException
si se llama a la interrupt
en el hilo en espera antes de que se complete el cálculo.
ExecutionException
lanzará ExecutionException
si el cómputo involucrado ( Task
en este caso) produce una excepción.
La forma en que quiera manejar esto dependerá completamente de su aplicación.
EDIT: Aquí hay 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";
}
}
}