Search code examples
javamultithreadingsynchronizationvolatile

Volatile keyword: is the variable I am using among two threads synchronized?


I have a code like the one below where an object is shared among two threads (the main thread and the Monitor thread). Do I have to declare MyObject globally and make it volatile to ensure it will be pushed to memory? Otherwise the if statement can print "Not null" if MyObject is only locally accessed by the thread and is not declared volatile, right?

public static void main(String[] args) {
    MyObject obj = MyObjectFactory.createObject();
    new Monitor(obj).start();
    Thread.sleep(500); 
    if(obj == null) 
        System.out.println("Null");
    else
        System.out.println("Not null");
}

public void doSomethingWithObject(MyObject obj) {
    obj = null;
}

private class Monitor extends Thread {
   public Monitor(MyObject obj) {
       this.obj=obj;
   } 
   public void run() {
       doSomethingWithObject(obj);
   }
}

Note: The code example may not compile since I wrote it myself here on Stackoverflow. Consider it as a mix of pseudo code and real code.


Solution

  • The instance is shared but the references to it are not. Example:

     String a = "hello";
     String b = a;
    
     b = null; // doesn't affect a
    

    a and b are references to the same instance; changing one reference has no effect on the instance or any other references to the same instance.

    So if you want to share state between threads, you will have to create a field inside MyObject which has to be volatile:

    class MyObject { public volatile int shared; }
    
    
    public void doSomethingWithObject(MyObject obj) {
        obj.shared = 1; // main() can see this
    }
    

    Note that volatile just works for some types (references and all primitives except long). Since this is easy to get wrong, you should have a look at types in java.util.concurrent.atomic.

    [EDIT] What I said above isn't correct. Instead, using volatile with long works as expected for Java 5 and better. This is the only way to ensure atomic read/writes for this type. See this question for references: Is there any point in using a volatile long?

    Kudos go to Affe for pointing that out. Thanks.