Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8097462

Task throws IllegalStateException on cancel

XMLWordPrintable

      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);
          }
      }

            msladecek Martin Sládeček
            fastegal Jeanette Winzenburg
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported: