了解JavaFX WebView线程模型

时间:2013-11-26 18:39:32

标签: java multithreading javafx

我试图了解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);
  }
}

1 个答案:

答案 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线程内执行长时间运行的任务的原因,如果您希望应用程序具有响应性