1

I'm developing application in JavaFX and I have the following structure with the object "config" which is created in the class Controller and then I'm accessing the config from the two classes which extend the original Controller class and also from other Thread.

public class Controller {

    protected Config config = new Config();

    private void setupConfig() {
        var machineStatus = new MachineStatus();
        machineStatus.setRemainingTime(25);
        machineStatus.setMessage("Running");
        config.setMachineStatus(machineStatus);
    }
}


public class MainController extends Controller {
    Thread taskThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    while(true) {
                        var newStatus = getNewStatus();          // Returns new status containing different RemainingTime and Message value every time
                        config.setMachineStatus(newStatus);
                        Thread.sleep(10000);
                    }
                }
    });
    taskThread.start();
}


public class StatusController extends Controller {
    System.out.println(config.getMachineStatus().getRemainingTime()) // Always prints 25
    System.out.println(config.getMachineStatus().getMessage())      // Always prints "Running"
}


public class Config {
    private MachineStatus machineStatus;

    public MachineStatus getMachineStatus() {
        return machineStatus;
    }

    public void setMachineStatus(MachineStatus value) {
        machineStatus = value;
    }
}

public class MachineStatus {
    private int remainingTime;
    private String message;

    public int getRemainingTime() {
        return remainingTime;
    }

    public void setRemainingTime(int value) {
        remainingTime = value;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String value) {
        message = value;
    }
}

I would like to achieve that when I call getRemainingTime() or get Message() in the StatusController, I will always get the latest status which was written in the config variable. But instead, I'm still getting the initial values which were stored when the variable was initialized.

The second Thread runs every 10 seconds and always updated the config variable with the new machine status. Even if I let the second Thread running for several minutes, in StatusController, I'm always getting the initial values.

Could someone help me how to achieve this?

Martin819
  • 412
  • 2
  • 7
  • 26
  • 2
    Do you start the thread `taskThread` somewhere? – akarnokd Jun 21 '22 at 13:10
  • Please provide Config class. Otherwise it will not be enough to answer your question. – Stanislau Kozel Jun 21 '22 at 13:10
  • 1
    We need to know [A] the source of the `Config` class, and [B] Your snippet does not indicate that the `taskThread` is ever actually started. Because there are 2 alternate explanations that would both explain what you are observing: [A] Your config class / those setters aren't properly synced up and you're running into JMM local caching characteristics reliably, and/or [B] you never even started that thread, and/or [C] the new status is always 'running' - note that you never set 'remaining time' to anything in the pasted code, or [D] something else not apparent in what you pasted. – rzwitserloot Jun 21 '22 at 13:17
  • @akarnokd Yes, thread is running, I know that for sure. I have edited the snippet. – Martin819 Jun 21 '22 at 13:19
  • @StanislauKozel I have added the Config class – Martin819 Jun 21 '22 at 13:19
  • @rzwitserloot I have edited my question to contain start of the Thread. It is definitely running. That I know for sure. I have also added the Config class. – Martin819 Jun 21 '22 at 13:20
  • 1
    You probably don't want to use inheritance here at all. Just define the two controller classes and give them a reference to the same `Config` instance. See, e.g., https://stackoverflow.com/questions/14187963/passing-parameters-javafx-fxml or https://stackoverflow.com/questions/32342864/applying-mvc-with-javafx. Your background thread should wrap the call to `config.setMachineStatus(machineStatus);` in `Platform.runLater(...)`, so the `Config` instance is only ever accessed from one thread. – James_D Jun 21 '22 at 16:51
  • 1
    It would seem you would be better off making use of the JavaFX animation facilities such as Timeline, but perhaps there is additional items in your actual app which lead you to the custom threaded solution. A JavaFX Task might be appropriate if you need multi threading, the Task javadoc outlines usage scenarios. – jewelsea Jun 21 '22 at 19:06

1 Answers1

6

Ah, got it. Looks like you think that StatusController and MainController access to the same instance of Config. But it doesn't work like that.

StatusController extends Controller
MainController extends Controller

Each controller have the own Config object instance. It means that MainController change config of MainController. But StatusController have the own Config. You need to have access to the Config of MainController and print their status.

The second issue. Config is not thread safe. You may not see changes of threads due to CPU cache and etc. You could use any synchronization concept for solving it.

rzwitserloot - Already answered...

  • Thank you. Could you please briefly mention the best way how to take care of the synchronization? – Martin819 Jun 21 '22 at 13:30
  • Better to start with accesing to the same Config. It will be enough for start. There are a lot of ways and the best way depends on requirements from that. From current example I will say that private MachineStatus machineStatus; -> private volatile MachineStatus machineStatus; will be enough. – Stanislau Kozel Jun 21 '22 at 13:34
  • 1
    Making `machineStatus` `volatile` won't really be enough, since it is mutable. Probably (depending on context) the easiest way is just to access the `Config` instance from a single thread, which is easily managed in the code in the original post. (Just wrap the update in `Platform.runLater()`) – James_D Jun 21 '22 at 16:56