Фоновый поток, напрямую обращающийся к пользовательскому интерфейсу в любом случае - PullRequest
0 голосов
/ 12 апреля 2019

Вот мой код, может кто-нибудь объяснить, почему он работает каждый раз?

package dingding;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;


public class Dingding extends Application {

    TextField tfAuto = new TextField("0");
    AutoRunThread runner = new AutoRunThread();
    boolean shouldStop = false;

    private class AutoRunThread extends Thread {

        @Override
        public void run() {
            while (true) {
                int i = Integer.parseInt(tfAuto.getText());
                ++i;
                tfAuto.setText(String.valueOf(i));
                try {
                Thread.sleep(1000);
                } catch (Throwable t) {

                }
                if (shouldStop) {
                    runner = null;
                    shouldStop = false;
                    return;
                }
            }
        }
    }

    @Override
    public void start(Stage primaryStage) {

        Button btnStart = new Button("Increment Automatically");
        Button btnStop = new Button("Stop Autotask");

        btnStart.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                if (runner == null) {
                    runner = new AutoRunThread();
                    runner.setDaemon(true);
                }
                if (runner != null && !(runner.isAlive())) {
                    runner.start();
                }
            }
        });

        btnStop.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                shouldStop = true;
            }
        });


        VBox rootBox = new VBox();
        HBox autoBox = new HBox();

        autoBox.getChildren().addAll(tfAuto, btnStart, btnStop);

        rootBox.getChildren().addAll(autoBox);

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

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

1 Ответ

3 голосов
/ 15 апреля 2019

Как я уже сказал в своем комментарии, неправильно синхронизированный код не гарантирует ошибок per se .Однако это не означает, что указанный код, когда он используется в многопоточном контексте, действительно работает - вам просто повезло.В конце концов вы столкнетесь с неопределенным поведением , таким как поврежденное состояние, устаревшие значения и неожиданные исключения.Это связано с тем, что без синхронизации действия, выполняемые одним потоком, не гарантируются видимыми для любого другого потока.Вам необходимо отношение случай-до , более подробно описанное в документации из java.util.concurrent и этого SO вопроса .

JavaFX, напримербольшинство фреймворков / инструментариев пользовательского интерфейса является однопоточным.Это означает, что существует специальный поток - в данном случае Поток приложения JavaFX - который отвечает за все действия, связанные с пользовательским интерфейсом 1 .Именно этот поток и только этот поток должен использоваться для доступа и / или изменения состояния, связанного с «живым» графом сцены (т. Е. Узлами, которые находятся в сцене, находящейся в окне, отображающем 2 ).Использование любого другого потока может привести к описанному выше неопределенному поведению .

Некоторые функции, связанные с пользовательским интерфейсом, фактически гарантируют, что они вызываются в потоке приложений JavaFX , обычно выбрасываяIllegalStateException, если нет.Тем не менее, оставшиеся функции позволят вам молча вызывать их из любого потока, но это не значит, что это безопасно.Я полагаю, что это делается таким образом, потому что проверка потока в каждой функции, связанной с пользовательским интерфейсом, является кошмаром обслуживания и требует немалых затрат производительности.


1.Это немного сложнее, чем это;JavaFX также имеет «поток визуализации призмы» и «поток мультимедиа».См. Понимание архитектуры JavaFX для получения дополнительной информации.Но обратите внимание, что, с точки зрения разработчика приложения, единственный поток, который имеет значение, это Поток приложения JavaFX .

2.Это задокументировано Node.Обратите внимание, что некоторые узлы, такие как WebView, более ограничены, когда дело доходит до многопоточности;это будет задокументировано в соответствующих местах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...