【问题标题】:visibility of data during(/after) thread execution线程执行期间(/之后)数据的可见性
【发布时间】:2014-02-11 16:55:28
【问题描述】:

在此示例中,有一个 Input 类和一个 Result 类的实例。 输入实例填充在一个 GUI 线程中,这里是 JavaFX 应用程序线程。 按下按钮后,此输入实例将在工作线程中使用。然后工作线程创建一个 Result 类的实例,并在调用此 Platform.runLater 以更新 GUI 后用一些值填充它。

我的第一个问题是: 是否保证工作线程看到 Input 实例的值?

我会说是的,原因如下: JLS 17.4.5。发生在订单之前,说: 线程上的 start() 调用发生在已启动线程中的任何操作之前。

所以从我的角度来看,JavaFX 线程 before start 中所做的一切都会被调用 对工作线程可见。

我的第二个问题是: 是否保证 JavaFX 应用程序线程可以看到 Result 实例的值?

我认为是的,但我不确定。 Platform.runLater 会确保这一点吗?如何?

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 + '}';
        }

    }

}

【问题讨论】:

    标签: java concurrency javafx


    【解决方案1】:

    是否保证工作线程看到 Input 实例的值?

    是的:Thread#start 创建了一个发生前的关系。所以你有:

    • input.setName("Jack");happens-before workerThread.start(); 因为它们都在 FX 线程上,所以你得到程序顺序的保证
    • workerThread.start();由于您提到的原因,在 result.setName(input.getName()); 之前发生(线程启动之前的所有操作都发生在该线程中执行的任何操作之前)

    是否保证 JavaFX 应用程序线程看到 Result 实例的值?

    是的,Platform.runLater 还提供了 the javadoc 暗示的发生前关系:“此方法 [...] 可以从任何线程调用”。如果你不相信你可以看看the code,你会发现有几个同步点。

    没有这种保证,如果不手动同步所有内容,就不可能与 JavaFX 组件进行通信。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-22
      • 2016-03-04
      • 1970-01-01
      • 1970-01-01
      • 2023-02-09
      • 2022-01-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多