为什么线程会阻塞我的JavaFX UI线程? [英] Why is a thread blocking my JavaFX UI Thread?

查看:846
本文介绍了为什么线程会阻塞我的JavaFX UI线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当用户选择在另一个线程中启动阻止进程的菜单项时,我试图在JavaFX 8应用程序中提供反馈。在我的实际应用程序中,它是一个文件下载,但我通过示例使用最小代码创建了一个测试用例:

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. 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();
    }
}

这是它应该如何工作:当你选择开始菜单项,主菜单文本应立即更改为正在运行...,然后它应附加完成!在模拟我的文件下载的5秒睡眠后。

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.

实际发生的是两个文本更新在之后 em>即使我使用 Platform.runLater(),阻塞过程也已完成。我做错了什么?

What is actually happening is both text updates are firing after the blocking process is done, even though I'm using Platform.runLater(). What am I doing wrong?

推荐答案

最简单的方法是使用任务。只有在需要从其他线程更新UI时才需要 Platform.runLater ,因此在您的情况下不需要。如果您想在后台任务运行时跟踪后台任务的进度,可以使用 updateMessage updateProgress 方法安全地将消息传递给UI线程而不用担心通过EDT进行调度的任务。您可以在此处找到有关此内容的更多信息,请访问 https://docs.oracle .com / javase / 8 / javafx / interoperability-tutorial / concurrency.htm

The easiest way to do this is by using a 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. 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. You may find more information on this here 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();
    }
}

这篇关于为什么线程会阻塞我的JavaFX UI线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆