Data visibility during (/ after) stream execution

In this example, there is an instance of the Input class and the Result class. The introductory instance is populated in the GUI-Thread, here is the JavaFX Application Thread. After clicking the button, this input instance is used in the workflow. The workflow then instantiates the Result class and populates it with some values ​​after this Platform.runLater is called to update the GUI.

My first question is: Is it guaranteed that the worker thread sees the values ​​of the Input instance?

I would say yes because of the following: JLS 17.4.5. It happens before the order, says: The start () call in the thread is called - before any actions in the running thread.

So, from my point of view, everything that was done at the beginning of JavaFX Thread before is called. will be visible to the workflow.

My second question: Is it guaranteed that the JavaFX Application Thread sees the values ​​of the result instance?

I think so, but I'm not sure. Will Platform.runLater guarantee this? How?

package javafxconcurrency;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class JavaFxConcurrency extends Application {

    private Input input;

    @Override
    public void start(Stage primaryStage) {
        input = new Input();
        input.setId(1);
        input.setName("Jack");

        Button btn = new Button();
        btn.setText("Start a thread");
        btn.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                Task<Result> task = new Task() {

                    @Override
                    protected Object call() throws Exception {
                        final Result result = queryDB(input);
                        Platform.runLater(new Runnable() {

                            @Override
                            public void run() {
                                updateGUI(result);
                            }

                        });
                        return result;
                    }

                    private Result queryDB(Input input) {
                        try {
                            Thread.sleep(3000);
                            Result result = new Result();
                            result.setId(System.currentTimeMillis());
                            result.setName(input.getName());
                            return result;
                        } catch (InterruptedException ex) {
                            throw new RuntimeException(ex);
                        }
                    }

                };
                Thread workerThread = new Thread(task);
                workerThread.setDaemon(true);
                workerThread.start();
            }

        });

        StackPane root = new StackPane();
        root.getChildren().add(btn);

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("Visibilty");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private void updateGUI(Result result) {
        System.out.println("result" + result);
    }

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

    private static class Input {

        private long id;

        private String name;

        public void setId(long id) {
            this.id = id;
        }

        public long getId() {
            return id;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

    }

    private static class Result {

        private long id;

        private String name;

        public void setId(long id) {
            this.id = id;
        }

        public long getId() {
            return id;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        @Override
        public String toString() {
            return "Result{" + "id=" + id + ", name=" + name + '}';
        }

    }

}
+4
source share
1 answer

Is it guaranteed that the worker thread sees the values ​​of the Input instance?

Yes: Thread#startraises the before-relationship event. So you have:

  • input.setName("Jack");happens before workerThread.start();, because they are both in the FX stream, so you get guarantees on the order in the program
  • workerThread.start(); - result.setName(input.getName()); , ( , ).

, JavaFX Application Thread ?

, Platform.runLater , javadoc: " [...] ". , , , .

JavaFX .

+4

Source: https://habr.com/ru/post/1526388/


All Articles