multithreadingjavafxjavafx-11

How to update a value in another thread from FX application thread?


I'm developing a simple TCP server application and my server code is in a thread called serverThread. I have a variable named response and it's initial value is an empty string but when the user clicks on Send button , the value will get change and this updating happens in GUI thread but I'm using this variable in serverThread so I want to update the value from GUI thread and I don't know how. Any solutions ? Thank you in advance !

This method will run in GUI thread :

public void sendResponseToClient(ActionEvent event) {
    this.response = responseTextField.getText();
}

And this is my server Thread :

serverThread = new Thread(() -> {
                try {

                    ServerSocket serverSocket = new ServerSocket(SERVER_PORT);

                    while (true) {

                        Socket server = serverSocket.accept();

                        Platform.runLater(() -> {
                            displayServerLog("Connected to " + server.getRemoteSocketAddress());
                            displayStatus(true);
                        });

                        PrintWriter toClient = new PrintWriter(server.getOutputStream() , true);
                        BufferedReader fromClient = new BufferedReader(new InputStreamReader(server.getInputStream()));

                        String line = fromClient.readLine();
                        Platform.runLater(() -> displayServerLog("Message from client : " + line));

                        if (!response.isBlank()) {
                            toClient.println(response);
                            Platform.runLater(() -> displayServerLog("Message to client : " + response));
                        }

                        if (response.equalsIgnoreCase("done")) {
                            toClient.println("Disconnecting ...");
                            Platform.runLater(() -> {
                                displayServerLog("Disconnecting ...");
                                displayStatus(false);
                            });
                            serverSocket.close();
                        }

                    }
                } catch (Exception e){
                    e.printStackTrace();
                }
            });
    serverThread.start();

Solution

  • Don't have time to write a more thorough answer, but I would use some kind of a BlockingQueue* to hand off the value. The GUI thread can call queue.put(responseTextField.getText()), and the server thread can do

    String localResponse = queue.poll();
    if (localResponse != null) {
        Platform.runLater(() -> displayServerLog("Message to client : " + localResponse));
        if (localResponse.equalsIgnoreCase("done")) {
            ...
        }
    }
    

    BlockingQueue generally is the first thing I reach for any time I want to send a message from one thread to another. Maybe it's not the best solution in every case, but I'm a big believer in first, get something working, and then worry about whether you can make it work better. BlockingQueue usually achieves the "get something working" step for me.


    * Probably a LinkedBlockingQueue, but I'm not expert on the intended uses of the different kinds of BlockingQueue.