I am currently hunting a nasty bug in a multi-threaded environment using FutureTasks and Executors. The basic idea is this to have a fixed number of threads execute individual FutureTasks that compute a result that is to be displayed in a a table (never mind the GUI aspect here).
I have been looking at this for so long, I am beginning to doubt my sanity.
Consider this piece of code:
public class MyTask extends FutureTask<Result> {
private String cellId;
...
protected void done() {
if (isCancelled()) return;
try {
Result r = get(); // should not wait, because we are done
... // some processing with r
sendMessage(cellId, r);
} catch (ExecutionException e) { // thrown from get
...
} catch (InterruptedException e) { // thrown from get
...
}
}
...
}
When done()
is called by an Executor handling an instance of MyTask, I check if I got there, because the task was cancelled. If so, I skip all remaining activities, especially I do not call sendMessage()
.
The documentation for FutureTask.done() says:
Protected method invoked when this task transitions to state isDone (whether normally or via cancellation). The default implementation does nothing. Subclasses may override this method to invoke completion callbacks or perform bookkeeping. Note that you can query status inside the implementation of this method to determine whether this task has been cancelled. (API Reference)
But what I do not get from the documentation of FutureTask
are the semantics while done()
is being executed. What if I pass the isCancelled()
check at the beginning, but right after that some other thread calls my cancel()
method? Will that cause my task to change its mind and reply isCancelled() == true
from then on?
If so, how would I later know if the the message was sent? Looking at isDone()
would just tell me that execution of the task was finished, but as isCancelled()
were true then as well, I could not know if it got to send the message out in time.
Maybe this is obvious, but I do not really see it right now.