-
Bug
-
Resolution: Duplicate
-
P4
-
None
-
8u5
When cancelling a Task, the exception property has the value IllegalStateException, when I expect it to have a value of null:
java.lang.IllegalStateException: Task must only be used from the FX Application Thread
at javafx.concurrent.Task.checkThread(Task.java:1219)
at javafx.concurrent.Task.getValue(Task.java:962)
at javafx.concurrent.Task$TaskCallable.call(Task.java:1446)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.lang.Thread.run(Thread.java:745)
Actually, in an earlier version it seems like it behaved as expected: see the Fig. 6.8 on page 273, chapter "Collections and Concurrency" in Pro JavaFX 2 by James Weaver.
Below is a runnable example that demonstrates the issue, using one of the examples in Task's api doc.
/*
* Created on 05.06.2013
*
*/
package chapter4layoutandcontrols;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.StringBinding;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.BorderPaneBuilder;
import javafx.scene.layout.HBox;
import javafx.scene.layout.HBoxBuilder;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
* Issue: Task throws IllegalStateException on cancel
*
* To reproduce:
* run, start, cancel - the listener to the exception property shows the message
* "Task must only be used from the FX Application Thread" (plus
* its stacktrace) though all access seems to be on the fx-thread.
*
* @author Jeanette Winzenburg, Berlin
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public class WorkerIllegalStateException extends Application {
private Task worker;
private Button startButton;
private Button cancelButton;
public WorkerIllegalStateException() {
worker = createTask();
}
// This is the example from java doc of Task
private Task createTask() {
Task<Integer> task = new Task<Integer>() {
@Override
protected Integer call() throws Exception {
int iterations;
for (iterations = 0; iterations < 1000; iterations++) {
if (isCancelled()) {
updateMessage("Cancelled at " + iterations);
break;
}
updateMessage("Iteration " + iterations);
updateProgress(iterations, 1000);
// Now block the thread for a short time, but be sure
// to check the interrupted exception for cancellation!
try {
Thread.sleep(100);
} catch (InterruptedException interrupted) {
if (isCancelled()) {
updateMessage("Cancelled at: " + iterations);
break;
}
}
}
return iterations;
}
};
return task;
}
private void hookupEvents() {
startButton.setOnAction(actionEvent -> new Thread(worker).start());
cancelButton.setOnAction(actionEvent -> worker.cancel());
startButton.disableProperty().bind(
worker.stateProperty().isNotEqualTo(Worker.State.READY));
cancelButton.disableProperty().bind(
worker.stateProperty().isNotEqualTo(Worker.State.RUNNING));
// listen to changes of the exception property
ChangeListener l = (observable, oldValue, newValue) -> {
if (!(newValue instanceof Throwable)) return;
((Throwable) newValue).printStackTrace();
};
worker.exceptionProperty().addListener(l);
}
private Parent createContent() {
startButton = new Button("Start");
cancelButton = new Button("Cancel");
hookupEvents();
Label message = new Label();
message.textProperty().bind(worker.messageProperty());
Label state = new Label();
state.textProperty().bind(Bindings.format("%s", worker.stateProperty()));
VBox topPane = new VBox(10);
topPane.setPadding(new Insets(10, 10, 10, 10));
topPane.setAlignment(Pos.CENTER);
topPane.getChildren().addAll(message, state);
HBox buttonPane = new HBox(10);
buttonPane.setPadding(new Insets(10, 10, 10, 10));
buttonPane.setAlignment(Pos.CENTER);
buttonPane.getChildren().addAll(startButton, cancelButton);
BorderPane pane = new BorderPane();
pane.setCenter(topPane);
pane.setBottom(buttonPane);
return pane;
}
@Override
public void start(Stage stage) throws Exception {
Scene scene = new Scene(createContent());
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
java.lang.IllegalStateException: Task must only be used from the FX Application Thread
at javafx.concurrent.Task.checkThread(Task.java:1219)
at javafx.concurrent.Task.getValue(Task.java:962)
at javafx.concurrent.Task$TaskCallable.call(Task.java:1446)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.lang.Thread.run(Thread.java:745)
Actually, in an earlier version it seems like it behaved as expected: see the Fig. 6.8 on page 273, chapter "Collections and Concurrency" in Pro JavaFX 2 by James Weaver.
Below is a runnable example that demonstrates the issue, using one of the examples in Task's api doc.
/*
* Created on 05.06.2013
*
*/
package chapter4layoutandcontrols;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.StringBinding;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.BorderPaneBuilder;
import javafx.scene.layout.HBox;
import javafx.scene.layout.HBoxBuilder;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
* Issue: Task throws IllegalStateException on cancel
*
* To reproduce:
* run, start, cancel - the listener to the exception property shows the message
* "Task must only be used from the FX Application Thread" (plus
* its stacktrace) though all access seems to be on the fx-thread.
*
* @author Jeanette Winzenburg, Berlin
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public class WorkerIllegalStateException extends Application {
private Task worker;
private Button startButton;
private Button cancelButton;
public WorkerIllegalStateException() {
worker = createTask();
}
// This is the example from java doc of Task
private Task createTask() {
Task<Integer> task = new Task<Integer>() {
@Override
protected Integer call() throws Exception {
int iterations;
for (iterations = 0; iterations < 1000; iterations++) {
if (isCancelled()) {
updateMessage("Cancelled at " + iterations);
break;
}
updateMessage("Iteration " + iterations);
updateProgress(iterations, 1000);
// Now block the thread for a short time, but be sure
// to check the interrupted exception for cancellation!
try {
Thread.sleep(100);
} catch (InterruptedException interrupted) {
if (isCancelled()) {
updateMessage("Cancelled at: " + iterations);
break;
}
}
}
return iterations;
}
};
return task;
}
private void hookupEvents() {
startButton.setOnAction(actionEvent -> new Thread(worker).start());
cancelButton.setOnAction(actionEvent -> worker.cancel());
startButton.disableProperty().bind(
worker.stateProperty().isNotEqualTo(Worker.State.READY));
cancelButton.disableProperty().bind(
worker.stateProperty().isNotEqualTo(Worker.State.RUNNING));
// listen to changes of the exception property
ChangeListener l = (observable, oldValue, newValue) -> {
if (!(newValue instanceof Throwable)) return;
((Throwable) newValue).printStackTrace();
};
worker.exceptionProperty().addListener(l);
}
private Parent createContent() {
startButton = new Button("Start");
cancelButton = new Button("Cancel");
hookupEvents();
Label message = new Label();
message.textProperty().bind(worker.messageProperty());
Label state = new Label();
state.textProperty().bind(Bindings.format("%s", worker.stateProperty()));
VBox topPane = new VBox(10);
topPane.setPadding(new Insets(10, 10, 10, 10));
topPane.setAlignment(Pos.CENTER);
topPane.getChildren().addAll(message, state);
HBox buttonPane = new HBox(10);
buttonPane.setPadding(new Insets(10, 10, 10, 10));
buttonPane.setAlignment(Pos.CENTER);
buttonPane.getChildren().addAll(startButton, cancelButton);
BorderPane pane = new BorderPane();
pane.setCenter(topPane);
pane.setBottom(buttonPane);
return pane;
}
@Override
public void start(Stage stage) throws Exception {
Scene scene = new Scene(createContent());
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
- duplicates
-
JDK-8092556 [Task] cancellation makes the Task code throw IllegalStateException
-
- Resolved
-