Estoy tratando de usar la ThreadPoolExecutor
clase de Java para ejecutar una gran cantidad de tareas pesadas con un número fijo de subprocesos. Cada una de las tareas tiene muchos lugares durante los cuales puede fallar debido a excepciones.
He subclasificado ThreadPoolExecutor
y he anulado el afterExecute
método que se supone que proporciona las excepciones no detectadas que se encuentran al ejecutar una tarea. Sin embargo, parece que no puedo hacer que funcione.
Por ejemplo:
public class ThreadPoolErrors extends ThreadPoolExecutor {
public ThreadPoolErrors() {
super( 1, // core threads
1, // max threads
1, // timeout
TimeUnit.MINUTES, // timeout units
new LinkedBlockingQueue<Runnable>() // work queue
);
}
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
if(t != null) {
System.out.println("Got an error: " + t);
} else {
System.out.println("Everything's fine--situation normal!");
}
}
public static void main( String [] args) {
ThreadPoolErrors threadPool = new ThreadPoolErrors();
threadPool.submit(
new Runnable() {
public void run() {
throw new RuntimeException("Ouch! Got an error.");
}
}
);
threadPool.shutdown();
}
}
El resultado de este programa es "Todo está bien, ¡situación normal!" aunque el único Runnable enviado al grupo de subprocesos arroja una excepción. ¿Alguna pista de lo que está pasando aquí?
¡Gracias!
Respuestas:
De los documentos :
Cuando envíe un Runnable, quedará envuelto en un Futuro.
Su afterExecute debería ser algo como esto:
fuente
future.isDone()
? ComoafterExecute
se ejecuta después de queRunnable
se completa, supongo quefuture.isDone()
siempre regresatrue
.ADVERTENCIA : Debe tenerse en cuenta que esta solución bloqueará el hilo de llamada.
Si desea excepciones de procesos lanzados por la tarea, a continuación, por lo general es mejor utilizar
Callable
en lugar deRunnable
.Callable.call()
se le permite lanzar excepciones marcadas, y estas se propagan nuevamente al hilo de llamada:Si
Callable.call()
arroja una excepción, esta será envuelta en unaExecutionException
y arrojada porFuture.get()
.Es probable que esto sea mucho más preferible que la subclase
ThreadPoolExecutor
. También le brinda la oportunidad de volver a enviar la tarea si la excepción es recuperable.fuente
future.get()
se llama a su versión sobrecargada.La explicación de este comportamiento está en el javadoc para afterExecute :
fuente
Lo solucioné envolviendo el ejecutable proporcionado enviado al ejecutor.
fuente
whenComplete()
método deCompletableFuture
.Estoy usando la
VerboseRunnable
clase de jcabi-log , que se traga todas las excepciones y las registra. Muy conveniente, por ejemplo:fuente
Otra solución sería utilizar ManagedTask y ManagedTaskListener .
Necesita un Callable o Runnable que implemente la interfaz ManagedTask .
El método
getManagedTaskListener
devuelve la instancia que desea.E implementa en ManagedTaskListener el
taskDone
método:Más detalles sobre el ciclo de vida de la tarea administrada y el oyente .
fuente
Esto funciona
Creará un ejecutor con un solo hilo, que puede realizar muchas tareas; y esperará a que el actual finalice la ejecución para comenzar con el siguiente
En caso de error o excepción de uncaugth, uncaughtExceptionHandler lo detectará
fuente
Si desea monitorear la ejecución de la tarea, puede girar 1 o 2 subprocesos (tal vez más dependiendo de la carga) y usarlos para tomar tareas de un contenedor ExecutionCompletionService.
fuente
Si
ExecutorService
proviene de una fuente externa (es decir, no es posible subclasificarThreadPoolExecutor
y anularafterExecute()
), puede usar un proxy dinámico para lograr el comportamiento deseado:fuente
Esto es debido a
AbstractExecutorService :: submit
que se envolver surunnable
enRunnableFuture
(nada másFutureTask
), como a continuaciónLuego
execute
lo pasaráWorker
yWorker.run()
llamará a la siguiente.fuente
Esto es similar a la solución de mmm, pero un poco más comprensible. Haga que sus tareas extiendan una clase abstracta que envuelve el método run ().
fuente
En lugar de subclasificar ThreadPoolExecutor, le proporcionaría una instancia de ThreadFactory que crea nuevos Threads y les proporciona un UncaughtExceptionHandler
fuente