JavaFX在jdk7上工作良好,但在jdk8上不工作:在FX应用程序线程上不工作
我最近遇到了这个问题: java.util.NoSuchElementException 线程“thread-4”java.lang.IllegalStateException中的异常:不在FX应用程序线程上;currentThread=Thread-4 代码在jdk7上工作,但在jdk8上不工作,代码如下所示: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
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对此进行了改进。