Skip to content

4 Terminación de un ejecutor

Terminación de un ejecutor

La interfaz ExecutorService extiende la interfaz Executor para proporcionar la funcionalidad que solvente las limitaciones de ésta última. Este aspecto es muy importante, ya que los ejecutores están diseñados de manera que si no se termina su ejecución explícitamente, el programa que lo uso nunca terminará, incluso aunque el ejecutor no tenga ninguna tarea para ejecutar, dado que los hilos del ejecutor seguirán vivos.

Por este motivo, la interfaz ExecutorService proporciona, entre otras cosas, una serie de métodos que permitan a la aplicación terminar (detener) un ejecutor y sus hilos, liberando los recursos obtenidos.

Veamos parte de la definición de la interfaz ExecutorService:

public interface ExecutorService extends Executor {

    // Métodos relacionados con el control del ciclo de vida de los ejecutores
    void shutdown();
    List<Runnable> shutdownNow();
    boolean isShutdown();
    boolean isTerminated();
    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;

    // ...

}

Así, tenemos el método shutdown(), que termina el ejecutor, de manera que ya no se aceptan más tareas nuevas en él, que son rechazadas, pero a las tareas que estuvieran ejecutándose o las que ya hubieran sido recibidas y aún no se hayan ejecutado se les permitirá concluir su ejecución. A este se le conoce como terminación "ordenada".

Pero si queremos llevar a cabo una terminación de ejecutor mucho más drástica, podemos llamar al método shutdownNow(), que termina el ejecutor inmediatamente, de manera que las nuevas tareas que le lleguen son rechazadas y los hilos del threadpool en los que se están ejecutando tareas en ese momento son marcados para interrupción, aunque no hay garantía de que las tareas decidan detectar la interrupción y finalizar su ejecución. Las tareas que estuvieran en el ejecutor pendientes de comenzar su ejecución no llegarán a ser ejecutadas, y se retornará un lista List<Runnable>con éstas. El método retorna inmediatamente, sin esperar a que las tareas que ya están en ejecución terminen de ejecutarse.

Si después de haber llamado al método shutdown() o shutdownNow() tratamos de enviar alguna otra tarea al ejecutor, ésta será rechazada y el ejecutor lanzará una excepción RejectedExecutionException en la llamada al método que ha sido usado para el envío.

Si queremos esperar a la terminación del ejecutor, es decir a que todas las tareas que gestiona terminen de ejecutarse, podemos llamar al método awaitTermination(long timeout, TimeUnit unit), que bloquea el hilo en el que se realiza la llamada hasta que las tareas del ejecutor hayan terminado o transcurre el tiempo máximo de espera (timeout). Este método retorna un booleano indicativo de si realmente terminó el ejecutor. Si se sobrepasa el tiempo de espera máximo se retornará false.

Debemos tener en cuenta que si llamamos a awaitTermination() sin haber llamado antes a shutdown() o shutdownNow(), la llamada a awaitTermination() retornará inmediatamente y no tendrá ningún efecto.

Una de las opciones recomendadas para terminar un ejecutor es usar una combinación de los métodos anteriores, tratando de finalizar el ejecutor de forma ordenada, esperando un tiempo prudencial a su terminación, transcurrido el cuál se fuerza la finalización:

executorService.shutdown();
try {
    if (!executorService.awaitTermination(1, TimeUnit.SECONDS)) {
        executorService.shutdownNow();
    } 
} catch (InterruptedException e) {
    executorService.shutdownNow();
}

Además tendremos disponibles otros métodos informativos relacionados con la finalización del ejecutor:

  • isShutdown(): Retorna true si se ha llamado al método shutdown() o shutdownNow() del ejecutor.
  • isTerminating(): Retorna true si el ejecutor está realizando la operación de finalizar su ejecución, después de haber sido llamado el método shutdown) o shutdownNow(), pero no ha concluido aún.
  • isTerminated(): Retorna true si se ha llamado al método shutdown() o shutdownNow() del ejecutor y todas las tareas han finalizado su ejecución.