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:
Runnable
or Callable
implementation does not check for interrupts and will run to completion even if you do interrupt it (here the interrupt makes no difference)cancel()
(again the interrupt makes no difference)try ... finally
for this.)cancel
at all)So when/why would you cancel a task without interrupting it?
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:
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:
Future.cancel(false)
would be correct:
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
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With