Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

  • The 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)
  • The task already completed before you called cancel() (again the interrupt makes no difference)
  • The task needs to perform some cleanup before it exits (a well-written implementation will use try ... finally for this.)
  • The task cannot terminate immediately and must continue to perform operations that would be affected by interrupts, e.g. blocking I/O (in this case you should probably not call cancel at all)

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

like image 997
finnw Avatar asked Jul 17 '10 12:07

finnw


2 Answers

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.
like image 164
Ryan Avatar answered Oct 22 '22 20:10

Ryan


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).

like image 45
abyx Avatar answered Oct 22 '22 20:10

abyx