Search code examples
javamultithreadingstaticvolatile

Using the same variables in two threads, but I don't know why they won't update in Java


I would like to start off by saying that I know there are similar questions to this. I did some searching, and I DID find some information. Unfortunately, the solutions did not help me. I do not know why. This is why I ask this question.

I have two Threads I am working with in Java. I have four classes that are related to this. The first class is the class with the 'main' method in it. It sets up and starts all the Threads. Here is how I start and declare the Threads:

Thread thread1 = new Thread(){
  public void run(){
    DeliverMessage deliverMess = new DeliverMessage();
    deliverMess.deliver();
  }
}

Thread thread2 = new Thread(){
  public void run(){
    Timing time = new Timing();
    time.controlTime();
  }
}
thread1.start();
thread2.start();

The second class contains all the global variables. This class is called 'GlobalVariables'. GlobalVariables:

public class GlobalVariables(){
  //Variables
  public boolean proceed;
  public boolean doubleCheck;
}

The other class, which is called 'DeliverMessage' is set up like this. This is one of the classes I have my problem with. DeliverMessage:

public class DeliverMessage(){
  //Variables
  String mess1 = "Hello";
  String mess2 = "How are you?";
  String mess3 = "Goodbye";
  //Setup
  GlobalVariables global = new GlobalVariables();

  public void deliver(){
    while(true){
      if(global.proceed){
        System.out.println(mess1);
      }
      if(global.doubleCheck){
        System.out.println(mess2);
        System.out.println(mess3);
      }
    }
  }

The last class I am having trouble with is called 'Timing'. I would like it to be able to change the boolean variables in order to control when the messages are delivered. Here it is:

public class Timing(){
  //Setup
  GlobalVariables global = new GlobalVariables();
  public void controlTime(){
    try {
        TimeUnit.SECONDS.sleep(4);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    global.proceed = true;
    try {
        TimeUnit.SECONDS.sleep(16);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    global.doubleCheck = true;
  }
}

I have looked into using 'volatile'. I did not find that worked. I tried declaring the variables in 'GlobalVariables' like this 'public volatile boolean proceed;'. I tried changing the variable, but the 'DeliverMessage' class did not register that change. I also tried doing the same thing with 'static'. That did not work either. The variables seem to change in the 'Timing' class, but they do not link to the SAME variables in the 'DeliverMessage' class.

Please let me know what I should do. Thanks in advance, ~Rane

EDIT: Thank you! I have a couple really quick clarifications though. 1) Do I declare the boolean variables as both 'static' and 'volatile'? 2) How do I refer to the variables in the 'DeliverMessage' and 'Timing' classes?


Solution

  • Your two classes, Timing and DeliverMessage each have their own unique instance of GlobalVariables, so changing the state of one GlobalVariables object will have no effect on the other GlobalVariables object. If you want them to share the same GlobalVariables instance, then give them the same instance.

    i.e., give them both a

    public void setGlobalVariables(GlobalVariables global) {
       this.global = global;
    }
    

    method and pass the same GlobalVariables instance into both Timing and DeliverMessage classes.

    final GlobalVariables global = new GlobalVariables();
    Thread thread1 = new Thread(){
      public void run(){
        DeliverMessage deliverMess = new DeliverMessage();
        deliverMess.setGlobalVariables(global);
        deliverMess.deliver();
      }
    }
    
    Thread thread2 = new Thread(){
      public void run(){
        Timing time = new Timing();
        time.setGlobalVariables(global);
        time.controlTime();
      }
    }
    thread1.start();
    thread2.start();
    

    And yes, make the GlobalVariables' boolean variables volatile, but that's still not your major issue.

    Note: another option is to pass the GlobalVariables instance into your class constructors.