如何为我的代码启动一个线程,为 JavaFX 应用程序启动一个线程?

Dav*_*son 2 java multithreading javafx-8

我正在尝试使用 JavaFX 运行程序。如果我使用 Swing,我会用 main 方法启动一个类,并让它构建 GUI 类。这会给我 2 个线程,应用程序的普通线程和 EventQueue。这将防止阻止 UI 工作。

因此,我尝试让在静态 main 方法中创建的类构造 Application 类,然后启动它。我得到了一个 RuntimeException,因为调用 launch 方法的程序不是 Application 的子类。

有没有办法分离线程,或者一切都必须在给定 Application 类的线程内工作?

Jam*_*s_D 6

在 JavaFX 中,我猜为了防止许多 Swing 应用程序中出现的非常常见的线程错误,启动过程受到限制,以便(或多或少)唯一的​​做事方式迫使您执行 UI 代码外汇应用线程:

public class MyAppStartClass extends Application {

    @Override
    public void start(Stage primaryStage) {
        // this method will be executed on the FX Application Thread

        // load UI and display it here....
    }

}
Run Code Online (Sandbox Code Playgroud)

在 Oracle JRE 中,执行java MyAppStartClass将(与常规 Java 应用程序相反)导致MyAppStartClass创建一个实例,启动 FX 应用程序线程,并start在 FX 应用程序线程上执行创建的实例的方法。(除此之外还有更多内容,但这是基本要点。)

如果您想支持不知道如何执行 JavaFX 应用程序(包括许多 IDE)的环境,您可以添加一个main强制执行此操作的方法,只需调用静态Application.launch()方法:

public class MyAppStartClass extends Application {

    @Override
    public void start(Stage primaryStage) {
        // this method will be executed on the FX Application Thread

        // load UI and display it here....
    }

    // to support non-JavaFX-aware environments:
    public static void main(String[] args) {
        launch(args);
    }

}
Run Code Online (Sandbox Code Playgroud)

请注意,有一个 的重载形式launch,您可以在其中指定一个Application子类,因此您可以拥有一个不同的主类(此用例很少):

public class MainClass {
    public static void main(String[] args) {
        Application.launch(MyAppStartClass.class, args);
    }
}
Run Code Online (Sandbox Code Playgroud)

该方法有两个重要特征launch需要注意:

  1. 每个JVM生命周期只能调用一次。第二次调用它会抛出异常。
  2. 它会一直阻塞,直到 JavaFX 平台退出。

如果你想让一个线程在 FX Application Thread 之外做工作,最简单的方法是直接从 start 方法启动它:

public class MyAppStartClass extends Application {

    @Override
    public void start(Stage primaryStage) {

        // start a background thread to do background stuff:

        new Thread(() -> {
            // background work...
        }).start();


        // UI work...
    }

}
Run Code Online (Sandbox Code Playgroud)

如果将其与 Swing 应用程序的标准启动进行比较:

public class MySwingApp {

    public static void main(String[] args) {

        SwingUtilities.invokeLater(() -> {
            // UI work...
        });

        // background work...
    }
}
Run Code Online (Sandbox Code Playgroud)

与 Swing 相比,这个过程有点颠倒。在 Swing 中,您(应该)明确地让启动方法 (main) 指定 UI 在 AWT 事件调度线程上运行,并且您可以在执行 main 的“当前”线程中执行其他操作。在 JavaFX 中,启动方法 (start) 是在 UI 线程上执行的,如果您想在另一个线程上执行操作,您可以显式启动一个。

其他规则几乎相同:作为场景图一部分的 UI 元素只能在 UI 线程等上进行修改。 注意 JavaFX 有一个特定的并发 API,用于管理后台线程中的任务并在 FX 应用程序上调度 UI 更新线。

在旁边:

从理论上讲,我想您可以执行以下操作:

public class MainClass {
    public static void main(String[] args) {
        new Thread(() -> Application.launch(MyAppStartClass.class, args)).start();

        // do "background thread" work here in the (now free) main thread
    }
}
Run Code Online (Sandbox Code Playgroud)

但由于该习语与通常的设置相去甚远,我不推荐它。尤其要注意,您不应该直接在Application子类中使用这样的 main 方法,因为(我认为)Oracle JRE(或知道如何运行 JavaFX 应用程序的环境)可能会忽略 main 方法并按照描述启动您的 start 方法在这篇文章的顶部。