Java 澄清何时何地启动和停止新线程

Java 澄清何时何地启动和停止新线程,java,javafx,Java,Javafx,我遵循了一个在线教程,为我的JavaFX应用程序构建了一个启动屏幕。以下是SplashController文件: package splash; import java.io.IOException; import javafx.application.Platform; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.scene.image.Im

我遵循了一个在线教程,为我的JavaFX应用程序构建了一个启动屏幕。以下是SplashController文件:

package splash;

import java.io.IOException;

import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

/**
 * SplashController controls the Splash.FXML file. This is the initial software display. After a 
 * designated amount of time, the MainMenu.FXML is run.  
 *
 */
public class SplashController {

@FXML 
private StackPane splashRoot;
@FXML
private ImageView splashImage;

/**
 * Called after all @FXML annotated members have been injected. Starts a new thread "SplashScreen()".
 */
@FXML void initialize() {

    new SplashScreen().start(); //Start SplashScreen thread.

}

/**
 * Inner class that extends thread. Displays the splash screen for a designated amount of time then loads
 * MainMenu.FXML, sets a new stage, and displays the main menu. Hides the splash screen.
 *
 */
class SplashScreen extends Thread {

    @Override
    public void run() {

        try {

            splashImage.fitWidthProperty().bind( splashRoot.widthProperty() );  // binds the image to the rootPane width.
            Thread.sleep( 3000 ); // puts the thread (SplashScreen) to sleep in order to allow the splash to display long enough.

            Platform.runLater( new Runnable() { // Forces the main menu scene to load onto the SplashScreen thread when it is available.

                @Override
                public void run() {

                    FXMLLoader loader = new FXMLLoader( getClass().getResource( "../mainMenu/MainMenu.FXML" ) ); // Places MainMenu.FXML into the loader.
                    Stage stage = new Stage(); // Creates a new stage.

                    try {

                        stage.setScene( new Scene( loader.load() )  ); // Sets the scene using the root node of the loaded FXML document.

                    } catch ( IOException e ) {

                        e.printStackTrace();

                    }

                    stage.setResizable(false); // Prevents user from resizing the window.
                    stage.setTitle( "Test" ); // Sets the stage title.
                    stage.show(); // Displays the stage.
                    splashRoot.getScene().getWindow().hide(); // Hides the splash screen and presumably ends the SplashScreen thread.

                }

            });

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

    }

} 
}
我试图解释我对线程如何工作的理解,希望您能为我澄清以下内容是否正确或回答问题:

1) 如果我从未创建任何扩展
thread
的新类,或者创建任何新的
Runnable()
对象,那么我可以假设JavaFX项目中的所有内容都在单个JavaFX应用程序线程上运行

2) 当我创建内部类
SplashScreen extends Thread
并对其调用
start()
时,我是否创建了第二个线程?因此,我有两个线程——常规JavaFX应用程序线程和
SplashScreen
线程

3) 然后,当我调用
Platform.runLater(new Runnable(){..})
时,它是在JavaFX应用程序线程、SplashScreen线程还是新的第三个线程中设置了新的stage、FXML和控制器

4) 当我调用splashRoot.getScene().getWindow().hide()时,SplashScreen线程是否结束了?还是该线程继续执行由
Platform.runLater()
调用的
new Runnable()

1) 如果我从未创建任何扩展线程或 创建任何新的Runnable()对象,我可以假设 我的JavaFX项目运行在一个JavaFX应用程序线程上

这是正确的,只要您不调用任何这样做的东西(例如,从其他API)

2) 创建内部类时,SplashScreen扩展线程并调用 开始(),我正在创建第二个线程吗?因此,我有两个问题 线程-常规JavaFX应用程序线程和SplashScreen 螺纹

对。请注意,
SplashScreen
在需要处理UI内容时使用
Platform.runLater()

3) 当我调用Platform.runLater(newrunnable(){….})时 它在JavaFX应用程序中设置了新的stage、FXML和控制器 线程,SplashScreen线程,还是新的第三个线程

调用
Platform.runLater()
的代码位于第二个线程上。
Platform.runLater()
中的
Runnable
对象是放在JavaFX应用程序线程“队列”中的对象,该线程将在完成其正在做或需要做的任何事情(即渲染UI等)后运行该队列

4) 当我调用splashRoot.getScene().getWindow().hide()时,是否结束 飞溅的丝网?或者,该线程是否继续使用新线程 平台调用的Runnable()。runLater()

它只需关闭承载启动屏幕的窗口。线程结束是因为它是线程必须执行的
Runnable
中的最后一行代码。线程结束是因为在将
Runnable
放入JavaFX应用程序线程队列之后没有其他事情要做

总结
  • 您创建了一个显示启动屏幕的窗口
  • 在控制器的构造函数中,您创建了另一个线程
  • 在该线程中,您让它(新线程)休眠3000毫秒
  • 在它被唤醒后,您将返回到JavaFX应用程序线程,在那里您将加载新内容并打开新窗口,并关闭启动屏幕
  • 1) 如果我从未创建任何扩展线程或 创建任何新的Runnable()对象,我可以假设 我的JavaFX项目运行在一个JavaFX应用程序线程上

    这是正确的,只要您不调用任何这样做的东西(例如,从其他API)

    2) 创建内部类时,SplashScreen扩展线程并调用 开始(),我正在创建第二个线程吗?因此,我有两个问题 线程-常规JavaFX应用程序线程和SplashScreen 螺纹

    对。请注意,
    SplashScreen
    在需要处理UI内容时使用
    Platform.runLater()

    3) 当我调用Platform.runLater(newrunnable(){….})时 它在JavaFX应用程序中设置了新的stage、FXML和控制器 线程,SplashScreen线程,还是新的第三个线程

    调用
    Platform.runLater()
    的代码位于第二个线程上。
    Platform.runLater()
    中的
    Runnable
    对象是放在JavaFX应用程序线程“队列”中的对象,该线程将在完成其正在做或需要做的任何事情(即渲染UI等)后运行该队列

    4) 当我调用splashRoot.getScene().getWindow().hide()时,是否结束 飞溅的丝网?或者,该线程是否继续使用新线程 平台调用的Runnable()。runLater()

    它只需关闭承载启动屏幕的窗口。线程结束是因为它是线程必须执行的
    Runnable
    中的最后一行代码。线程结束是因为在将
    Runnable
    放入JavaFX应用程序线程队列之后没有其他事情要做

    总结
  • 您创建了一个显示启动屏幕的窗口
  • 在控制器的构造函数中,您创建了另一个线程
  • 在该线程中,您让它(新线程)休眠3000毫秒
  • 在它被唤醒后,您将返回到JavaFX应用程序线程,在那里您将加载新内容并打开新窗口,并关闭启动屏幕

  • 啊,谢谢你!很好的解释——再澄清一点:为什么在醒来后,它会移回JavaFX应用程序线程?所有对
    Platform.runLater()
    的调用是否都已排队等待应用程序线程?@DylanRussell在
    thread.sleep()
    之后要做的下一件事是调用
    Platform.runLater()
    ,因此整个块都已排队等待应用程序线程。事实上,该线程在将
    Runnable
    添加到队列regardl后立即结束