简体   繁体   English

为什么线程阻塞了我的JavaFX UI线程?

[英]Why is a thread blocking my JavaFX UI Thread?

I am trying to provide feedback in a JavaFX 8 application when a user chooses a menu item that launches a blocking process in another thread. 当用户选择在另一个线程中启动阻止进程的菜单项时,我试图在JavaFX 8应用程序中提供反馈。 In my real application it's a file download, but I have created a test case using minimal code by way of example: 在我的实际应用程序中,它是一个文件下载,但我通过示例使用最小代码创建了一个测试用例:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.MenuButton;
import javafx.scene.control.ToolBar;
import javafx.scene.control.MenuItem;
import javafx.stage.Stage;

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

    @Override
    public void start(Stage primaryStage) throws Exception {
        MenuItem menuItem = new MenuItem("Start");
        MenuButton menuButton = new MenuButton();
        menuButton.setText("Async Process");
        menuButton.getItems().addAll(menuItem);

        menuItem.setOnAction(event -> {
            menuButton.setText("Running...");

            Platform.runLater(() -> {
                try {
                    // Simulate a blocking process
                    Thread.sleep(5000);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                menuButton.setText(menuButton.getText() + "Done!");
            });
        });

        final ToolBar toolbar = new ToolBar(menuButton);
        final Scene scene = new Scene(toolbar);
        primaryStage.setScene(scene);
        primaryStage.setWidth(150);
        primaryStage.show();
    }
}

Here's how it's supposed to work: When you select the "Start" menu item, the main menu text should immediately change to "Running...", and then it should append "Done!" 这是它应该如何工作:当您选择“开始”菜单项时,主菜单文本应立即更改为“正在运行...”,然后它应附加“完成!” after the 5-second sleep that simulates my file download. 在模拟我的文件下载的5秒睡眠之后。

What is actually happening is both text updates are firing after the blocking process is done, even though I'm using Platform.runLater() . 什么是实际发生的情况是这两个文本的阻塞进程完成更新射击,即使我使用Platform.runLater() What am I doing wrong? 我究竟做错了什么?

The easiest way to do this is by using a Task . 最简单的方法是使用Task Platform.runLater is only needed if you need to update the UI from a different thread and therefore is not necessary in your case. 只有在需要从其他线程更新UI时才需要Platform.runLater ,因此在您的情况下不需要。 If you would like to track progress of the background task while it is running, you may use updateMessage and updateProgress methods in the task to safely pass messages to the UI thread without worrying about the scheduling via EDT. 如果要在后台任务运行时跟踪后台任务的进度,可以在任务中使用updateMessageupdateProgress方法将消息安全地传递给UI线程,而不必担心通过EDT进行调度。 You may find more information on this here https://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm . 您可以在https://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm找到更多相关信息。

See the minimal working example below. 请参阅下面的最小工作示例。

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ToolBar;
import javafx.stage.Stage;


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

    @Override
    public void start(Stage primaryStage) throws Exception {
        MenuItem menuItem = new MenuItem("Start");
        MenuButton menuButton = new MenuButton();
        menuButton.setText("Async Process");
        menuButton.getItems().addAll(menuItem);

        menuItem.setOnAction(event -> {
            menuButton.setText("Running...");

            Task task = new Task<Void>() {
                @Override
                public Void call() {
                    //SIMULATE A FILE DOWNLOAD
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return null;
                }
            };
            task.setOnSucceeded(taskFinishEvent -> menuButton.setText(menuButton.getText() + "Done!"));
            new Thread(task).start();
        });

        final ToolBar toolbar = new ToolBar(menuButton);
        final Scene scene = new Scene(toolbar);
        primaryStage.setScene(scene);
        primaryStage.setWidth(150);
        primaryStage.show();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM