Skip to content

17 Cancelación de tareas y terminación del ScheduledThreadPoolExecutor

Cancelación de tareas y terminación del ScheduledThreadPoolExecutor

Cuando marcamos como cancelada una tarea del ejecutor llamando al método cancel() del ScheduledFuture correspondiente, si dicha tarea estaba deshabilitada para ejecución esperando que transcurriera el delayed indicado cuando se envió, la tarea nunca llegará a ejecutarse.

Por defecto, las tareas canceladas no son inmediatamente eliminadas de la work queue, sino que se espera a que transcurra el delay especificado cuando se enviaron. Sin embargo podemos cambiar dicha política llamando al método setRemoveOnCancelPolicy(true), que hará que se eliminen inmediatamente. Este método está disponible desde Java 7.

Cuando llamamos al método shutdown() para finalizar el ScheduledThreadPoolExecutor, al igual que ocurría con la clase ThreadPoolExecutor, se dejarán de aceptar nuevas tareas, por lo que si se le envían nuevas tareas éstas son rechazadas. Además, por defecto, se permitirá completar su ejecución tanto las tareas que ya estén en ejecución como aquellas que estén esperando para comenzar su ejecución, incluso las que estén deshabilitadas para ejecución en ese momento al no haber transcurrido aún el delay especificado cuando se enviaron.

Sin embargo, la clase ScheduledThreadPoolExecutor nos permite cambiar la política concreta de qué hacer con las tareas que están deshabilitadas para ejecución cuando se llama a shutdown(). Así, si llamamos al método setExecuteExistingDelayedTasksAfterShutdownPolicy(false) configuraremos el ejecutor para que dichas tareas no lleguen a ser ejecutadas.

De forma similar, mediante el método setContinueExistingPeriodicTasksAfterShutdownPolicy(false) podemos hacer que las tareas periódicas esperando la siguiente ejecución no lleguen a ser ejecutadas más.

Si llamamos al método shutdownNow(mayInterruptIfRunning), en vez de a shutdown(), el funcionamiento de este método será exactamente igual que en el caso de ThreadPoolExecutor, es decir, todas las tareas pendientes de ejecución, periódicas o no, no llegarán a ejecutarse, independientemente de las políticas establecidas anteriormente.

Proyecto CancelPeriodicTask

En este proyecto modificamos el proyecto anterior para cancelar la tarea periódica antes de terminar el ejecutor.

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

class Main {

    public static void main(String[] args) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
        ScheduledThreadPoolExecutor scheduledExecutor =
                (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(1);
        scheduledExecutor.setContinueExistingPeriodicTasksAfterShutdownPolicy(false);
        scheduledExecutor.setRemoveOnCancelPolicy(true);
        GreetTask greetTask = new GreetTask("Hello");
        int periodSeconds = 5;
        ScheduledFuture<?> greetScheduledFuture =
                scheduledExecutor.scheduleAtFixedRate(greetTask, 5, periodSeconds, TimeUnit.SECONDS);
        System.out.printf("%s -> %s - Greet task sent to be executed every %d seconds. Still %d seconds left to first ejecution\n",
                Thread.currentThread().getName(),
                dateTimeFormatter.format(LocalTime.now()),
                periodSeconds,
                greetScheduledFuture.getDelay(TimeUnit.SECONDS));
        int sleepSeconds = 25;
        try {
            TimeUnit.SECONDS.sleep(sleepSeconds);
        } catch (InterruptedException ignored) {
        } finally {
            greetScheduledFuture.cancel(true);
            System.out.printf("%s -> %s - Greet periodic task cancelled after %d seconds\n",
                    Thread.currentThread().getName(),
                    dateTimeFormatter.format(LocalTime.now()),
                    sleepSeconds);
            scheduledExecutor.shutdownNow();
        }
    }

}
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

class GreetTask implements Runnable {

    private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
    private final String greet;

    @SuppressWarnings("SameParameterValue")
    GreetTask(String greet) {
        this.greet = greet;
    }

    @Override
    public void run() {
        System.out.printf("%s -> %s - %s\n",
                Thread.currentThread().getName(),
                dateTimeFormatter.format(LocalTime.now()),
                greet);
    }

}