1 回答
TA贡献1860条经验 获得超8个赞
您绝不能在JavaFX 应用程序线程上运行长时间运行的任务。这样做将阻止所述线程执行任何导致 UI 冻结的与 GUI 相关的事情。这让您的用户感到难过。但是,您尝试将长时间运行的任务放在后台任务上是有缺陷的。您调用Thread.joinwhich 将阻塞调用线程,直到目标线程死亡;这实际上与在调用线程上运行任务相同。
为了快速修复您的示例,您可以执行以下操作:
@FXML
private void test(){
textField.setText("Pending...");
Thread t = new Thread(){
@Override public void run(){
boolean passed = doStuff();
Platform.runLater(() -> {
if(passed){
textField.setText("OK");
} else {
textField.setText("Error");
}
});
}
};
t.start();
}
这将创建一个线程,启动它,让它在后台运行,同时让JavaFX 应用程序线程继续做它需要做的事情。在后台线程内部,您必须更新TextField内部Platform.runLater(Runnable)调用。这是必需的,因为您绝不能从 JavaFX 应用程序线程以外的线程更新实时场景图;这样做会导致未定义的行为。此外,您应该查看Java 中的“实现可运行”与“扩展线程”。这样做更好,或者至少更惯用:
Thread t = new Thread(() -> { /* background code */ });
您还可以使用 a javafx.concurrent.Task,它可以更轻松地与JavaFX Application Thread进行通信。一种选择是:
@FXML
private void test(){
textField.setText("Pending...");
Task<Boolean> task = new Task<>() {
@Override protected Boolean call() throws Exception {
return doStuff();
}
};
task.setOnSucceeded(event -> textField.setText(task.getValue() ? "Ok" : "Error"));
new Thread(task).start();
}
您还可以将 绑定TextField到方法的message属性并在方法内Task调用。如果可能,您甚至可以提供更详细的消息。updateMessage("Pending...")call
也就是说,Thread自己创建和启动 s 并不理想,您应该研究线程池(使用类似 an 的东西ExecutorService)。您可能还想研究javafx.concurrent.Service“重用” Tasks。
有关 JavaFX 并发的更多信息,请参阅 JavaFX中的并发并阅读javafx.concurrent. 有关 Java 中多线程的基础知识,请参阅课程: Java™ 教程中的并发。
添加回答
举报