小编典典

JavaFX可以在jdk7上正常运行,但不能在jdk8上正常运行:在FX应用程序线程上无效

java

我最近遇到了这个问题:

java.util.NoSuchElementException线程“
Thread-4”中的异常java.lang.IllegalStateException:不在FX应用程序线程上;仅在FX应用程序线程上有效。currentThread
=线程4

该代码适用于jdk7,但不适用于jdk8,该代码如下所示:

public class myThread extends Thread {
    TextArea ta;
    String foo;
    connect(String foo, TextArea ta){
        this.ta = ta;
        this.foo = foo;
    }
    @Override
    public void run{
        Scanner scanner = new Scanner(foo);
        scanner.next();
        ta.appendText(scanner.next());
    }
}

然后我从以下代码中调用此线程:

    public class myApp extends Application {

        @Override
        public void start(Stage stage) {
            TextArea ta = new TextArea();
            TextField tf = new TextField
            Pane root = new Pane();
            root.getChildren().addAll(ta,tf);
            Scene scene = new Scene(root);
            stage.setScene(scene);
            stage.show();

            tf.setOnAction((javafx.event.ActionEvent event) -> {
                String foo = tf.getText();
                tf.clear();
                new myThread(foo,ta).start();
            });
        }

        public static void main(String[] args) {
            launch(args);
        }
    }

我要做的就是从其他具有功能的线程中更改控件的值/属性,就像在我的示例中一样,它扫描下一个字符串,然后将其附加到TextArea。

为什么它可以在jdk7上运行但不能在jdk8上运行?请 说明…

我已经进行了一些研究,并提出了解决JavaFX任务和服务的解决方案,但是我没有得到它们,网上也没有很好的例子。

请帮助…谢谢…


阅读 510

收藏
2020-11-30

共1个答案

小编典典

您的代码实际上在JDK7上也被破坏了。从后台线程(即不是从FX Application
Thread)更改UI控件的状态是非法的。与几乎所有UI工具包一样,JavaFX使用单线程模型,并且不提供UI元素的同步。因此,如果您从FX
Application Thread之外的其他线程更改或查看UI控件的状态,则您的代码容易发生未指定且不可预测的行为。

在JavaFX 2.2和更早版本(与JDK 7一起提供)中,很少有运行时检查来检查代码是否在正确的线程上执行。因此,您不会在JDK
7中遇到运行时异常,但是如上所述,您的代码有错误,并且结果不确定。在JavaFX
8中,对API进行了改进,以便(在大多数情况下)违反此规则将引发IllegalStateException。(这更好,因为您立即知道出了点问题。)

解决方法是更新FX Application Thread上的UI控件:

final TextArea ta = new TextArea() ;

// ...

Platform.runLater(new Runnable() {
    @Override
    public void run() {
        ta.appendText(scanner.next());
    }
});

如果现在仅使用Java 8,则可以使用lambda表达式替换匿名内部类:

Platform.runLater(() -> ta.appendText(scanner.next()));

ta尽管仍然有限制,但不再需要声明为final了)。

2020-11-30