javathreadpoolexecutorscheduledexecutorservice

When to use ScheduledThreadPoolExecutor's "removeOnCancel" Policy


The Javadocs for Java's ScheduledThreadPoolExecutor state the following:

When a submitted task is cancelled before it is run, execution is suppressed. By default, such a cancelled task is not automatically removed from the work queue until its delay elapses. While this enables further inspection and monitoring, it may also cause unbounded retention of cancelled tasks. To avoid this, set setRemoveOnCancelPolicy(boolean) to true, which causes tasks to be immediately removed from the work queue at time of cancellation.

I interpret this as meaning that

Question

Are there any consequences to setting the removeOnCancelPolicy to true?

I'm considering doing it in order to make sure that the work queue doesn't get too large and take up too much memory, but I'm confused as to why this policy isn't on by default.


Solution

  • Cancelling

    A task is cancelled by invoking method Future.cancel(boolean).

    So suppose you scheduled a task by schedule which implies a delay on the queue until execution starts:

    Creates and executes a one-shot action that becomes enabled after the given delay.

    Runnable task = new Callable<String>() {
        public String call() { return "Hello Future World!"; }
    };
    
    Future<String> future = executor.schedule(task, 50L, TimeUnit.SECONDS);
    future.cancel(true);
    

    The task is pushed to the work queue of this executor and waits there for execution (at least the specified delay of 50L, SECONDS). During this duration, you can cancel it. But depending on the removeOnCancelPolicy policy it either remains on the queue until execution would start (false) or it will be removed immediately (true).

    Purge (related design considerations)

    The behaviour depends on policy removeOnCancel of class ScheduledThreadPoolExecutor - see implementation of this inner-class method ScheduledFutureTask.cancel

    public boolean cancel(boolean mayInterruptIfRunning) {
        boolean cancelled = super.cancel(mayInterruptIfRunning);
        if (cancelled && removeOnCancel && heapIndex >= 0)
            remove(this);
        return cancelled;
    }
    

    The design considers this. See the parent class ThreadPoolExecutor's methods remove(runnable) and especially purge():

    Tries to remove from the work queue all Future tasks that have been cancelled. This method can be useful as a storage reclamation operation, that has no other impact on functionality. Cancelled tasks are never executed, but may accumulate in work queues until worker threads can actively remove them. Invoking this method instead tries to remove them now. However, this method may fail to remove tasks in the presence of interference by other threads.

    Queues as scarce resource

    A queue, especially a blocking-queue is somehow limited (e.g. in capacity: holds max items) why you should always strive to keep them short, not too much work load queued up, process tasks as fast as possible.

    Thus the docs warned about removeOnCancelPolicy set false:

    may also cause unbounded retention of cancelled tasks

    So the policy has impact on the queue, its fill-level (max capacity), possible rejection of further submitted tasks, etc.

    You could experiment the behaviour of this policy, by inspecting the underlying BlockingQueue of your executor: its size, the elements of Future on it. Their isCancelled state, etc.

    Use case: view cancelled tasks and beyond

    If the queue retains cancelled tasks then this allows to put the user in control (Usability principle), re-/un-do effort can be reduced, rescheduling can be a useful feature (as following example illustrates).

    Cancelling a task

    Suppose you have a report-scheduler with a some UI. When a user schedules a report then the report will be submitted (with some delay) to your executor/queue.

    Given the user scheduled a report and a second later recognizes that it got the wrong parameters. Because they will cause the report to run very long, they immediately cancel the scheduled report. Lucky they were, that it wasn't too late.

    Now: This means additional effort, because the wrong parameters must be corrected or reentered and the report scheduled again.

    Rescheduling a task

    Instead of entering all the parameters again, they want to reschedule the existing canceled one, and just modify a few parameters before clicking on "Submit" or "Schedule".

    Not forgotten, forgiven!

    If the policy removeOnCancelPolicy is set to false

    this enables further inspection and monitoring

    A view lists all tasks, filtered by status (canceled, scheduled, running, completed, etc.), so that the canceled one can be selected and its details (schedule, parameters) can be viewed. Additionally the action "Reschedule" makes it easy to submit it again.