



With a busy rest of the summer ahead of us, it was good to get another mountain done. Hopefully we'll find some time in the superior hiking months of September and October to knock off a few more!
java.util.concurrent
package, it becomes a simple, yet powerful tool.Future
interface that slightly diminishes its power. I found myself in a situation where I wanted to cancel a Future
, but then still wait until its associated task has completed. Initially I thought this might be accomplished with something like this: // send an interrupt to the task's thread
future.cancel(true);
// block until the task is complete
boolean finished = false;
boolean interrupted = false;
while (!finished) {
try {
future.get();
finished = true;
} catch (CancellationException ce) {
// task has been cancelled, handle appropriately
finished = true;
} catch (ExecutionException ee) {
// task completed with error, handle appropriately
finished = true;
} catch (InterruptedException ie) {
// current thread has been interrupted, record and continue
interrupted = true;
}
}
// re-interrupt this thread if we've been interrupted
if (interrupted) {
Thread.currentThread().interrupt();
}
cancel(true)
on the Future
in order to send an interrupt to the associated task's thread. Then call get()
on the Future
in a loop to ensure that the task has properly handled the interruption and completed execution before proceeding. However, the above code does not work as expected. The problem is that once you call cancel()
on a Future
, the task's thread will be sent an interrupt if it is running, but then the state associated with the task is completely cast aside. Subsequent calls to get()
on the same Future
will always immediately throw a CancellationException
and there is no available mechanism to block until the task's thread has completed handling the interruption and finished its execution.cancel()
method is very clear that if the task has not started, it will prevent it from starting, but if it has already started, it can make an attempt to "cancel" it via interruption of the task's thread. Of course, since in Java interrupting a thread is only a suggestion for it to actually stop what it's doing, there's no guarantee about when or if the task will actually stop unless you handle the interruption properly. Therefore, I hoped that calling get()
would wait for the computation to complete, and then throw a CancellationException
if the thread was interrupted. After testing it and also digging through the Java source code for the Future
implementation, I discovered that that is definitely not the case.ThreadPoolExecutor
. It takes a little more work then I had hoped, but using those hooks allows you to augment the functionality of ThreadPoolExecutor
to achieve this type of behavior. I'll leave the details of it up to you.Future
!