java - try - ¿Por qué la interfaz ExecutorService no implementa AutoCloseable?
try() (4)
Si no se llama a shutdown()
en un ejecutor de hilos, se producirá una aplicación que nunca termina. La mejor práctica para cerrar el servicio de ejecución es la siguiente:
ExecutorService service = null;
try {
service = Executors.newSingleThreadExecutor();
// Add tasks to thread executor
…
} finally {
if(service != null) service.shutdown();
}
Ya que Java conoce el concepto de probar con recursos, ¿no sería bueno si pudiéramos hacer esto?
try (service = Executors.newSingleThreadExecutor())
{
// Add tasks to thread executor
…
}
Ese ExecutorService tiene en realidad dos métodos relacionados con el cierre; basado en el simple hecho de que ambas formas de cerrar un servicio tienen sentido.
Por lo tanto, ¿cómo cerrarías automáticamente un servicio? ¿De una manera consistente que funcione para todos?
Entonces, la explicación razonable a mis ojos: no puede hacer que un ExecutorService sea AutoClosable porque ese servicio no tiene una sola operación de "cierre"; pero dos!
¡Y si cree que podría hacer un buen uso de este servicio de cierre automático, escribir su propia implementación usando "delegación" sería una cosa de 5 minutos! O probablemente 10 minutos, ya que crearía una versión llamando a shutdown()
como una operación de cierre; y uno que hace shutdownNow()
lugar.
Esta es una solución mediocre
ExecutorService service = Executors.newSingleThreadExecutor();
try (Closeable close = service::shutdown) {
}
Por supuesto, nunca debe poner nada entre la asignación y la declaración de try
, ni usar la variable local de service
después de la instrucción de try
.
Teniendo en cuenta las advertencias, simplemente use finally
lugar.
No veo donde AutoCloseable es tan útil para un Ejecutor. try-with-resources es para cosas que pueden inicializarse, usarse y liberarse dentro del alcance de un método. Esto funciona muy bien para cosas como archivos, conexiones de red, recursos jdbc, etc., donde se abren, utilizan y limpian rápidamente. Pero un ejecutor, especialmente un conjunto de subprocesos, es algo que desea que esté disponible durante un período de tiempo prolongado, probablemente durante la vida útil de la aplicación, y tenderá a inyectarse en servicios como singleton, que pueden tener un método que el marco DI sabe llamar al cierre de la aplicación para limpiar el ejecutor. Este patrón de uso funciona bien sin intentar con recursos.
Además, un gran motivador detrás de try-with-resources es asegurarse de que las excepciones no se oculten. Eso no es una consideración tanto para los ejecutores, todo el lanzamiento de excepciones se realizará en las tareas enviadas al ejecutor, el enmascaramiento de excepciones no es un problema.
Try-with-resources se trata de un cierre automático de Readers / Streams, mientras que ExecutorService se trata de ejecutar tareas utilizando un grupo de subprocesos.
Por lo tanto, no estoy seguro de que exista un paralelismo entre los dos que podamos pensar en aplicar también try-with-resources a ExecutorServices.
ACTUALIZADO
Citando la especificación del lenguaje Java:
Una instrucción try-with-resources está parametrizada con variables (conocidas como recursos) que se inicializan antes de la ejecución del bloque try y se cierran automáticamente, en el orden inverso al que se inicializaron, después de la ejecución del bloque try. Las cláusulas catch y una cláusula finally a menudo son innecesarias cuando los recursos se cierran automáticamente.
La especificación llama a las variables como "recursos" . Por lo tanto, no estoy seguro de si se puede llamar a ExecutorService como un recurso y, por lo tanto, no creo que ExecutorService sea paralelo a los Lectores / Secuencias / Declaración / Resultado / Configuración / Conexión, etc.