Code to reproduce:
@Override public void start(Stage stage) throws ExecutionException, InterruptedException {
Task task = new Task() {
@Override
protected Object call() throws Exception {
cancel();
return null;
}
};
Service service = new Service() {
@Override
protected Task createTask() {
return task;
}
};
task.stateProperty().addListener((ob, o, n) -> {
if ( n == Worker.State.CANCELLED) {
System.out.println("Task cancelled");
}
});
task.exceptionProperty().addListener(new ChangeListener<Throwable>() {
@Override
public void changed(ObservableValue ob, Throwable o, Throwable n) {
System.out.println("Exception set:");
n.printStackTrace(System.out);
Platform.exit();
}
});
service.start();
}
When a Task is cancelled, task.getValue() is called in the Executor (i.e. outside of App thread), but getValue() checks for FX thread, which results in the following Exception instead of returning the value:
java.lang.IllegalStateException: Task must only be used from the FX Application Thread
at javafx.concurrent.Task.checkThread(Task.java:1209)
at javafx.concurrent.Task.getValue(Task.java:962)
at javafx.concurrent.Task$TaskCallable.call(Task.java:1432)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at javafx.concurrent.Service.lambda$null$209(Service.java:724)
at javafx.concurrent.Service$$Lambda$65/955538869.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at javafx.concurrent.Service.lambda$executeTask$210(Service.java:723)
at javafx.concurrent.Service$$Lambda$63/1990188857.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:744)
@Override public void start(Stage stage) throws ExecutionException, InterruptedException {
Task task = new Task() {
@Override
protected Object call() throws Exception {
cancel();
return null;
}
};
Service service = new Service() {
@Override
protected Task createTask() {
return task;
}
};
task.stateProperty().addListener((ob, o, n) -> {
if ( n == Worker.State.CANCELLED) {
System.out.println("Task cancelled");
}
});
task.exceptionProperty().addListener(new ChangeListener<Throwable>() {
@Override
public void changed(ObservableValue ob, Throwable o, Throwable n) {
System.out.println("Exception set:");
n.printStackTrace(System.out);
Platform.exit();
}
});
service.start();
}
When a Task is cancelled, task.getValue() is called in the Executor (i.e. outside of App thread), but getValue() checks for FX thread, which results in the following Exception instead of returning the value:
java.lang.IllegalStateException: Task must only be used from the FX Application Thread
at javafx.concurrent.Task.checkThread(Task.java:1209)
at javafx.concurrent.Task.getValue(Task.java:962)
at javafx.concurrent.Task$TaskCallable.call(Task.java:1432)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at javafx.concurrent.Service.lambda$null$209(Service.java:724)
at javafx.concurrent.Service$$Lambda$65/955538869.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at javafx.concurrent.Service.lambda$executeTask$210(Service.java:723)
at javafx.concurrent.Service$$Lambda$63/1990188857.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:744)
- duplicates
-
JDK-8097462 Task throws IllegalStateException on cancel
- Closed