The term JavaFX concurrency refers to how JavaFX is designed with respect to multithreading and concurrency. In this JavaFX concurrency tutorial I will explain the JavaFX threading model.

If you are new to Java concurrency and multithreading, I have a longer Java Concurrency tutorial explaining how it works in richer detail than what there is space for in this text.

Single-threaded Rendering

JavaFX uses a single-threaded rendering design, meaning only a single thread can render anything on the screen, and that is the JavaFX application thread. In fact, only the JavaFX application thread is allowed to make any changes to the JavaFX Scene Graph in general.

A single-threaded rendering design is easier to implement correctly, but long-running tasks that run within the JavaFX application thread make the GUI unresponsive until the task is completed. No JavaFX GUI controls react to mouse clicks, mouse over, keyboard input while the JavaFX application thread is busy running that task.

Platform.runLater()

Sometimes you absolutely need to perform some long-running task in a JavaFX application. You don't want to leave the GUI unresponsive while the task is running, so you want to run the ask in its own thread. However, you would like the running task to update the GUI - either along the way, or when the task is completed. The task thread cannot update the GUI (the scene graph) directly - but JavaFX has a solution for this problem.

JavaFX contains the Platform class which has a runLater() method. The runLater() method takes a Runnable which is executed by the JavaFX application thread when it has time. From inside this Runnable you can modify the JavaFX scene graph. Here is an example showing a task thread updating a JavaFX ProgressBar while it is executing - by calling Platform.runLater() and update the ProgressBar control from in there:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class ConcurrencyExample extends Application {
  public static void main(String[] args) {
    launch(args);
  }

  @Override
  public void start(Stage primaryStage) {
    primaryStage.setTitle("JavaFX App");

    ProgressBar progressBar = new ProgressBar(0);

    VBox vBox = new VBox(progressBar);
    Scene scene = new Scene(vBox, 960, 600);

    primaryStage.setScene(scene);
    primaryStage.show();

    Thread taskThread = new Thread(new Runnable() {
      @Override
      public void run() {
        double progress = 0;
        for(int i=0; i<10; i++){

          try {
            Thread.sleep(1000);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }

          progress += 0.1;
          final double reportedProgress = progress;

          Platform.runLater(new Runnable() {
            @Override
            public void run() {
              progressBar
                  .setProgress(reportedProgress);
            }
          });
        }
      }
    });

    taskThread.start();
  }
}