Reputation: 48619
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?
Upvotes: 17
Views: 8281
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
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:
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:
Upvotes: 22
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