JavaFX在jdk7上工作良好,但在jdk8上不工作:在FX应用程序线程上不工作

JavaFX在jdk7上工作良好,但在jdk8上不工作:在FX应用程序线程上不工作,java,multithreading,javafx,Java,Multithreading,Javafx,我最近遇到了这个问题: java.util.NoSuchElementException 线程“thread-4”java.lang.IllegalStateException中的异常:不在FX应用程序线程上;currentThread=Thread-4 代码在jdk7上工作,但在jdk8上不工作,代码如下所示: public class myThread extends Thread { TextArea ta; String foo; connect(String f

我最近遇到了这个问题:

java.util.NoSuchElementException 线程“thread-4”java.lang.IllegalStateException中的异常:不在FX应用程序线程上;currentThread=Thread-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任务和服务的解决方案,但是,我没有得到它们,网上也没有好的例子


请帮忙。。。谢谢……

对JavaFX场景图的所有更改都必须在FX应用程序线程上进行。这意味着,当您定义自己的线程(执行一些工作,然后希望将其工作呈现给UI)时,您必须在FX应用程序线程上执行呈现部分

在您的例子中,实现这一点的最简单方法是在Runnable中移动UI更新部分(将结果附加到textarea),这必须从FX应用程序线程启动。这可以通过在平台内调用新定义的Runnable来完成。runLater()


老实说,我不知道为什么您的方法在Java7中有效,自从afaik以来,这种行为没有任何改变。要获得有关JavaFX任务的更多信息,您可以查看。

对JavaFX场景图的所有更改都必须在FX应用程序线程上进行。这意味着,当您定义自己的线程(执行一些工作,然后希望将其工作呈现给UI)时,您必须在FX应用程序线程上执行呈现部分

在您的例子中,实现这一点的最简单方法是在Runnable中移动UI更新部分(将结果附加到textarea),这必须从FX应用程序线程启动。这可以通过在平台内调用新定义的Runnable来完成。runLater()


老实说,我不知道为什么您的方法在Java7中有效,自从afaik以来,这种行为没有任何改变。要获得有关JavaFX任务的更多信息,您可以查看。

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

在JavaFX2.2和更早版本(JDK7附带)中,很少有运行时检查代码是否在正确的线程上执行。因此,在JDK 7中不会出现运行时异常,但正如前面提到的,您的代码有缺陷,结果不确定。在JavaFX8中,API得到了改进,因此(在大多数情况下)违反此规则会引发
IllegalStateException
。(这更好,因为您可以立即知道有什么问题。)

修复方法是更新FX应用程序线程上的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,尽管仍然有限制)。

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

在JavaFX2.2和更早版本(JDK7附带)中,很少有运行时检查代码是否在正确的线程上执行。因此,在JDK 7中不会出现运行时异常,但正如前面提到的,您的代码有缺陷,结果不确定。在JavaFX8中,API得到了改进,因此(在大多数情况下)违反此规则会引发
IllegalStateException
。(这更好,因为您可以立即知道有什么问题。)

修复方法是更新FX应用程序线程上的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,尽管仍有一些限制)。

它以前工作的原因是JavaFX2.x没有执行很多线程访问检查。这在JavaFX8中得到了改进。它以前工作的原因是JavaFX2.x没有做很多线程访问检查。JavaFX8对此进行了改进。