如何在JavaFX中进行多线程处理

4

我正在创建一个 JavaFX 应用程序,我需要GUI与类中的一些其他代码进行交互,但显然GUI和其他代码块不能在同一个线程上运行,因此我需要为它们分别创建不同的 Thread

public class Client extends Application {
public static void main(String[] args){
    launch(args);
}
@Override
public void start(Stage primaryStage){
    primaryStage.setTitle("Hello world!");
    Button btn = new Button();
    btn.setText("Run Client");

    btn.setOnAction(new EventHandler<ActionEvent>() {
        @Override
        public void handle(ActionEvent event) {
            try{runClient();}catch (Exception e){System.out.println("Exception Occurred, Server is down.");}
        }
    });


    StackPane root = new StackPane();
    root.getChildren().addAll(btn);
    primaryStage.setScene(new Scene(root, 500, 500));
    primaryStage.show();
}



public void runClient() throws Exception {
    String sentence;
    String modSentence;
    BufferedReader inFromUser = new BufferedReader( new InputStreamReader(System.in));
    Socket clientSocket = new Socket("localhost", 6789);
    DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
    BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
    sentence = inFromUser.readLine();
    outToServer.writeBytes(sentence + "\n");
    modSentence = inFromServer.readLine();
    System.out.println("From Server: " + modSentence);
    clientSocket.close();
}

runClient() 是客户端,需要GUI与客户端通讯,但是我无法创建一个新的Thread来同时运行它们。


为什么你不能创建一个新的线程? - Nicolas Filotto
1
您可以创建任意数量的线程,但最好使用ExecutorService;唯一需要注意的是所有GUI任务都应该在GUI线程上执行(请参见Platform#runLater)。 - fge
你能展示给我如何做吗?我不确定应该放在哪里。 - Kevin Hernandez
这是JavaFX软件设计的基本方面,因此最好从阅读相关信息开始,由其制造商提供。https://docs.oracle.com/javase/8/javafx/interoperability-tutorial/concurrency.htm否则,您将永远不会理解其背后的概念。 - mipa
1个回答

3
这是我认为你所需要的。您可以创建一个ExecutorService来处理多线程。然后使用execute()方法向其中提交任务。您可以在链接中了解基础知识。
如果您想要在FXThread之外进行一些UI操作,只需调用: Platform.runLater(some Runnable with GUI code); 它将在FXThread上运行。
public class Client extends Application {
    //Create a ExecutorService threadpool
    ExecutorService threadPool = Executors.newWorkStealingPool();

    public static void main(String[] args){
        launch(args);
    }

    @Override
    public void start(Stage primaryStage){
        primaryStage.setTitle("Hello world!");
        Button btn = new Button();
        btn.setText("Run Client");

        btn.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                try {
                    //submit a new task to the threadPool which will be executed on another thread.
                    threadPool.execute(new Runnable() {
                        @Override
                        public void run() {
                            runClient();
                        }
                    });
                } catch (Exception e) {
                    System.out.println("Exception Occurred, Server is down.");
                }
            }
        });

        StackPane root = new StackPane();
        root.getChildren().addAll(btn);
        primaryStage.setScene(new Scene(root, 500, 500));
        primaryStage.show();
    }

    public void runClient() throws Exception {
        String sentence;
        String modSentence;
        BufferedReader inFromUser = new BufferedReader( new InputStreamReader(System.in));
        Socket clientSocket = new Socket("localhost", 6789);
        DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
        BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        sentence = inFromUser.readLine();
        outToServer.writeBytes(sentence + "\n");
        modSentence = inFromServer.readLine();
        System.out.println("From Server: " + modSentence);
        clientSocket.close();

        //############# Run something in the FXThread #############\\
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                //do some UI stuff like updating labels
            }
        });
    }
}

编辑:
你应该使用哪个ExecutorService取决于你编写的应用程序类型。WorkStealing可能不适合你,但我不知道你的整体应用程序的情况,所以这只是一个例子。你可以在 这里 阅读更多关于不同线程池的信息。

编辑2:
如果你使用JavaFX-8,你可以使用Lambdas,它可以让你的代码更短。你可以这样写:

Platform.runLater(() -> {
    //DO STUFF HERE
});

或者

threadPool.execute(() -> {
    runClient();
});

或者

btn.setOnAction(event -> {
    try {
        ...
    } catch(Exception e) {
        ...
    }
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接