JavaFX:仅在更新标签时不在应用程序线程中?

标签 java multithreading javafx properties fxml

过去几天我一直在尝试 JavaFX、FXML、任务和属性。我偶然发现了一种奇怪的行为,希望您能帮助我更好地了解发生了什么。

我有一个简约的 GUI,如下所示: GUI

如果我单击按钮,则会创建并启动一个新任务。此任务递增 Double 属性,并将新值写入标签上并设置在进度栏中。任务的代码可以在这里看到:

public class TestTask extends Task<Void>{

    private final DoubleProperty doubleValue = new SimpleDoubleProperty();

    @Override
    protected Void call() throws Exception {
        for(double i = 0.1; i <= 1; i = i+0.1 ) {
            doubleValue.set(i);
            Thread.sleep(1000);
        }
        return null;
    }

    public DoubleProperty test() {
        return doubleValue;
    }
}

FXML Controller 的代码如下:

public class FXMLDocumentController implements Initializable {

    @FXML private Label label;
    @FXML private Slider slider;

    //Called when the Button is clicked
    @FXML
    private void handleButtonAction(ActionEvent event) {
        TestTask task =  new TestTask();
        task.test().addListener((ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> {
            //Works without problems
            slider.setValue(newValue.doubleValue());
            //Throws an exception
            label.setText("Value" + newValue.doubleValue());
        });
        new Thread(task).start();
    }
}

如果我运行此代码,尝试更新标签会导致以下异常:java.lang.IllegalStateException:不在 FX 应用程序线程上;当前线程 = 线程 4。 slider 的更新工作正常并且不会抛出任何错误。

阅读以下有关 SO 的问题后:

我知道标签的更新失败,因为我试图在监听器中执行 UI 更新,该更新是从 TestTask 线程而不是从 FXApplication 线程调用的。

我现在的问题是:为什么 slider 的更新可以工作并且不会引发异常?更新是在监听器内执行的,因此是在 TestTask 线程内执行的。此尝试是否还应该引发“不在 FX 应用程序线程上”异常?

预先感谢您抽出时间来帮助我。

最佳答案

在监听另一个线程上的属性更改时更新一个线程上的属性只是 race condition 。不要这样做。

JavaFX 系统不仅假设 UI 的更新发生在单个线程上,而且还假设属性的更新发生在单个线程上,无论它们是否绑定(bind)到 UI 元素。不要依赖 JavaFX 系统来检查所有竞争条件并为您正确报告和处理它们,因为它的设计目的不是这样做。

您需要以防止出现此类情况的方式编写代码

关于JavaFX:仅在更新标签时不在应用程序线程中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46993547/

相关文章:

java - 无法通过 Java 发送电子邮件

.net - RegisterWaitForSingleObject 与 AutoResetEvent

Java FX 应用程序在 LINUX 中意外关闭

JavaFX 多任务

java - 尝试在 hibernate/spring 中创建用户登录的东西

java - Android - 在 HTC 手机中录音

java - 使用 Java 注释计算排列

java - 设计问题 - servlet 中异步请求的线程安全

python - 线程条件变量 : un-acquired lock

java - 如何使用带有标签的形状位置