finnw
finnw

Reputation: 48619

Use case for Future.cancel(false)?

In what situation would one want to pass false for the mayInterruptIfRunning parameter to Future.cancel()?

If I understand correctly, if you pass false and the task is cancelled but the thread is not interrupted, the result (or ExecutionException) will never be accessible because the task is still marked as cancelled (i.e. isCancelled() returns true and get() throws CancellationException.)

Other possible situations are:

So when/why would you cancel a task without interrupting it?

Upvotes: 17

Views: 8281

Answers (3)

Jeremy Salwen
Jeremy Salwen

Reputation: 8430

I have a use case that might be interesting to you: I have a single thread that is executing a set of scheduled tasks. One of the tasks may be rescheduled by either itself or another task.

To do this, I use Future.cancel(false) on the existing copy in the queue, and then schedule the task for the new time.

If this code is called from the scheduled task itself, the cancel operation will be a no-op, and the task will be scheduled to run again in the future. If the code is called from another context, the upcoming task hasn't started execution yet, so it will be canceled, and replaced with a task scheduled for the new time.

Upvotes: 1

Ryan
Ryan

Reputation: 2091

tl;dr; Future.cancel(false) is only useful to avoid starting tasks that hadn't already been started.

There are two important things to understand regarding concurrency and cancellation.

The first is that in Java cancellation is purely cooperative. Java signals the cancellation request by having blocking methods throw InterruptedExcetions and by setting a flag on the Thread. The task implementation is responsible for noticing the cancellation request AND cancelling itself. Brian Goetz explains interruption in his post Dealing with InterruptedException. Not all task implementations will correctly handle interruption.

The second thing to point out is that the Future object is a placeholder for the results from a task to be executed in the future. If you don't have alot of threads running it is possible that the task starts executing right away but its also possible that all the threads are already being used and the task has to wait. Just because you have a reference to a Future object that doesn't mean that the corresponding task has actually started running. Its sort of like a reservation.

You have a Future object but the task could be in one of the following states:

  1. Waiting. For example it might be in a queue of other tasks waiting for processor time.
  2. Running.
  3. Completed.

If your task is in the first state "Waiting" then both Future.cancel(true) and Future.cancel(false) will mark the future as cancelled. The task remains in the queue of tasks to execute but when the executor gets to the task it notices the cancelled flag and skips it.

If your task is in the third state "Completed" than both Future.cancel(true) and Future.cancel(false) return false and don't do anything. Which makes sense because they are already done and there isn't a way to undo them.

The mayInterruptIfRunning flag is only important if your task is in the second state "Running".

If your task is running and mayInterruptIfRunning is false then the executor doesn't do anything and allows the task to complete.

If your task is running and mayInterruptIfRunning is true then the executor will interrupt the task. But remember the bit about cooperative cancellation - for the interruption to work the task has to have been implemented to handle cancellation.

Summary:

Future.cancel(true) is appropriate when:

  1. The Future represents a long running task that is known to have been implemented to handle interruption.

Future.cancel(false) would be correct:

  1. The task implementation cannot handle being interrupted.
  2. Its unknown if the task implementation supports cancellation.
  3. You are willing to wait for already started tasks to complete.

Upvotes: 22

abyx
abyx

Reputation: 72808

If you're afraid interrupting the task's execution might leave things in a bad state, and you simply want to mark it as canceled so that users of the Future will be aware of it (e.g. they should know the statistics requested weren't performed on time).

Writing threaded code that handles interrupts correctly is not trivial at all, and so one might simply prefer to avoid it.

Some information can be found here, here and of course in the great book Concurrent Programming in Java (by the guy who originally wrote java.util.concurrent).

Upvotes: 10

Related Questions