我试图了解JavaFX线程的工作原理。描述here没有多大帮助。
例如,在下面的代码中,打印顺序始终为A
,然后是B
,然后是Z
,这表明load()
调用和changed()
内的代码1}}正在同一个线程上运行。
但是我不明白,为什么线程不会在最后Thread.sleep(2000)
之后退出(因为没有更多的工作要做)?
我希望changed()
内的代码每次都在一个新的线程上运行,并且完全混淆它是如何工作的!
public class Test extends Application {
@Override
public void start(Stage stage) throws Exception {
final WebView webView = new WebView();
Scene scene = new Scene(webView);
stage.setScene(scene);
stage.show();
webView.getEngine().getLoadWorker().stateProperty()
.addListener(new ChangeListener<State>() {
@Override
public void changed(ObservableValue<? extends State> ov, State t, State t1) {
if (t1 == Worker.State.SUCCEEDED) {
System.out.println("Z"); // <---
}
}
});
webView.getEngine().load("http://www.google.com");
System.out.println("A"); // <---
Thread.sleep(2000);
System.out.println("B"); // <---
Thread.sleep(2000);
}
public static void main(String[] args) {
launch(args);
}
}
答案 0 :(得分:3)
start()
和changed()
从“JavaFX应用程序线程”运行。该线程负责监视事件的UI,将它们分派给用户代码并重新绘制UI。与Runnable.run()
不同,当退出时,线程终止,start()
由“JavaFX应用程序线程”调用,类似于循环:当start()
结束时,执行下一次迭代。 (实际上迭代是异步运行/等待事件,以免占用所有CPU资源,但循环可以作为简化模型。)
我将尝试更详细地解释一下。
将打印语句放置为(无法突出显示):
public void start(Stage stage) throws Exception {
System.out.println("2: " + Thread.currentThread().getName());
...
webView.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {
@Override
public void changed(ObservableValue<? extends State> ov, State t, State t1) {
if (t1 == Worker.State.SUCCEEDED) {
System.out.println("3: " + Thread.currentThread().getName());
System.out.println("Z"); // <---
}
}
});
webView.getEngine().load("...");
System.out.println("A"); // <---
Thread.sleep(2000);
System.out.println("B"); // <---
Thread.sleep(2000);
}
public static void main(String[] args) {
System.out.println("1: " + Thread.currentThread().getName());
launch(args);
System.out.println("4: " + Thread.currentThread().getName());
}
观察控制台和应用程序:
用户操作:启动应用程序
控制台:以下立即:
1: main
2: JavaFX Application Thread
应用程序:主窗口出现...但没有内容!为什么?因为负责绘制UI的“JavaFX应用程序线程”是sleep()
- 在点“A”之前。
控制台:2秒后打印“A” 应用程序:仍为“B”睡觉,窗口中仍然没有内容
控制台:2秒后打印“B” 应用程序:事物变得生动,内容开始充实; <{1}}中不再阻止UI线程,因此可以自由地完成其工作。
请注意,尽管sleep()
已结束,但start()
NOT ,因此主线程仍处于活动状态,因此应用程序处于活动状态。过了一会儿,页面加载了:
控制台:
launch()
用户操作:按关闭
控制台:
3: JavaFX Application Thread
Z
应用程序:窗口关闭,应用程序退出
要更深入地了解此主题,您可以在4: main
和main()
中放置断点,并观察活动的各种线程。
注释:来自UI线程中start()
调用的观察行为是您必须永远不能在UI线程内执行长时间运行的任务的原因,如果您希望应用程序具有响应性