Looking at the javafx.concurrent.Task code, I see the following in the nested 
class TaskCallable<V>’s call() method:

            try {
                final V result = task.call();
                if (!task.isCancelled()) {
                    // If it was not cancelled, then we take the return
                    // value and set it as the result.
                    task.runLater(new Runnable() {
                        @Override public void run() {
                            // The result must be set first, so that when the
                            // SUCCEEDED flag is set, the value will be 
                            // The alternative is not the case, because you
                            // can assume if the result is set, it has
                            // succeeded.
                    return result;
                } else {
                    // There may have been some intermediate result in the
                    // task set from the background thread, so I want to be
                    // sure to return the most recent intermediate value
                    return task.getValue();
            } catch (final Throwable th) {


When this code is executed off the JavaFX Application Thread, which I take to 
be the case almost all the time, the “task.getValue()” call will always throw 
an exception as the getValue() method does a checkThread() first.  Is this 

The practical implication is that a cancelled task, in addition to its state 
being CANCELLED, also has an IllegalStateException with a message of “Task must 
only be used from the FX Application Thread” recorded as an exception of the 
task if the task chooses to exit the call() method normally when the task is 
cancelled.  And of course, if the task chooses to exit the call() method 
abruptly by throwing its own RuntimeException, that runtime exception will be 
recorded as the exception of the task instead of the ISE.


Weiqi Gao

Reply via email to