What is the best way to manage multithreading in JavaFX 8?

北战南征 提交于 2019-12-03 08:05:33

In addition to using the low-level Thread API and Platform.runLater(...) to schedule code to be executed on the FX Application Thread, as in Tomas' answer, another option is to use the FX concurrency API. This provides Service and Task classes, which are intended to be executed on background threads, along with callback methods which are guaranteed to be executed on the FX Application Thread.

For your simple example, this looks like a bit too much boilerplate code, but for real application code it is quite nice, providing a clean separation between the background task and the UI update that is performed on completion. Additionally, Tasks can be submitted to Executors.

import javafx.application.Application;
import javafx.concurrent.Task ;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

public class ClassApplication extends Application {

    private Pane pane;

    public Parent createContent() {

        /* layout */
        BorderPane layout = new BorderPane();

        /* layout -> center */
        pane = new Pane();
        pane.setMinWidth(250);
        pane.setMaxWidth(250);
        pane.setMinHeight(250);
        pane.setMaxHeight(250);
        pane.setStyle("-fx-background-color: #000000;");

        /* layout -> center -> pane */
        Circle circle = new Circle(125, 125, 10, Color.WHITE);

        /* add items to the layout */
        pane.getChildren().add(circle);

        layout.setCenter(pane);
        return layout;
    }

    @Override
    public void start(Stage stage) throws Exception {
        stage.setScene(new Scene(createContent()));
        stage.setWidth(300);
        stage.setHeight(300);
        stage.show();

        Task<Void> task = new Task<Void>() {
            @Override
            public Void call() throws Exception {
                Thread.sleep(2000);
                return null ;
            }
        };

        task.setOnSucceeded(event -> {
            Circle circle = new Circle(50, 50, 10, Color.RED);
            pane.getChildren().setAll(circle);
        });

        new Thread(task).run();
    }

    public static void main(String args[]) {
        launch(args);
    }
}

If all you are doing is pausing, you can even get away with using (or abusing?) the animation API. There's a PauseTransition that pauses for a specified time, and you can use its onFinished handler to execute the update:

import javafx.application.Application;
import javafx.animation.PauseTransition ;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration ;

public class ClassApplication extends Application {

    private Pane pane;

    public Parent createContent() {

        /* layout */
        BorderPane layout = new BorderPane();

        /* layout -> center */
        pane = new Pane();
        pane.setMinWidth(250);
        pane.setMaxWidth(250);
        pane.setMinHeight(250);
        pane.setMaxHeight(250);
        pane.setStyle("-fx-background-color: #000000;");

        /* layout -> center -> pane */
        Circle circle = new Circle(125, 125, 10, Color.WHITE);

        /* add items to the layout */
        pane.getChildren().add(circle);

        layout.setCenter(pane);
        return layout;
    }

    @Override
    public void start(Stage stage) throws Exception {
        stage.setScene(new Scene(createContent()));
        stage.setWidth(300);
        stage.setHeight(300);
        stage.show();

        PauseTransition pause = new PauseTransition(Duration.millis(2000));
        pause.setOnFinished(event -> pane.getChildren().setAll(new Circle(50, 50, 10, Color.RED)));
        pause.play();
    }

    public static void main(String args[]) {
        launch(args);
    }
}

If you need to execute the pause multiple times, you can use a Timeline, and call setCycleCount(...):

import javafx.application.Application;
import javafx.animation.Timeline ;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration ;

public class ClassApplication extends Application {

    private Pane pane;

    public Parent createContent() {

        /* layout */
        BorderPane layout = new BorderPane();

        /* layout -> center */
        pane = new Pane();
        pane.setMinWidth(250);
        pane.setMaxWidth(250);
        pane.setMinHeight(250);
        pane.setMaxHeight(250);
        pane.setStyle("-fx-background-color: #000000;");

        /* layout -> center -> pane */
        Circle circle = new Circle(125, 125, 10, Color.WHITE);

        /* add items to the layout */
        pane.getChildren().add(circle);

        layout.setCenter(pane);
        return layout;
    }

    @Override
    public void start(Stage stage) throws Exception {
        stage.setScene(new Scene(createContent()));
        stage.setWidth(300);
        stage.setHeight(300);
        stage.show();

        KeyFrame keyFrame = new KeyFrame(Duration.millis(2000), 
            event -> pane.getChildren().setAll(new Circle(50, 50, 10, Color.RED)));
        Timeline timeline = new Timeline(keyFrame);

        // Repeat 10 times:
        timeline.setCycleCount(10);

        timeline.play();
    }

    public static void main(String args[]) {
        launch(args);
    }
}

You can access the scene only from the JavaFX application thread. You need to wrap your code that accesses the scene graph in Platform.runLater():

Platform.runLater(() -> {
    Circle circle = new Circle(50, 50, 10, Color.RED);
    pane.getChildren().clear();
    pane.getChildren().add(circle);
});
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!