Search code examples
javamultithreadingconcurrencyvolatile

Volatility of objects other than class variables


I used to believe that any variable that is shared between two threads, can be cached thread-locally and should be declared as volatile. But that belief has been challenged recently by a teammate. We are trying to figure out whether volatile is required in the following case or not.

class Class1
{
   void Method1()
   {
      Worker worker = new Worker();
      worker.start();
      ...
      System.out.println(worker.value); // want to poll value at this instant
      ...
   }

   class Worker extends Thread
   {
      int value = 0; // Should this be declared as a volatile?
      public void run()
      {
         ...
         value = 1; // this is the only piece of code that updates value
         ...
       }
   }
}

Now my contention is that, it is possible that the Worker (child) thread could have cached the variable "value" of the Worker object within the thread and updated just it's copy while setting the value to 1. In such a case, main thread may not see the updated value.

But my teammate believes that since the access to "value" is happening through an object (worker), therefore for both the threads to see different values, it could only be possible if both the threads were maintaining separate copies of "worker" object itself (which would further mean that creation of a thread involves creating a deep copy of all the shared objects).

Now I know that that can't be true, for it would be highly inefficient for each thread to maintain wholly different copies of all shared objects. So hence, I am in serious doubt. Does doing a "worker.value" in the main thread reference a different memory location than doing a "this.value" in the child thread? Will the child (Worker) thread cache "value"?

Regards.


Solution

  • Now my contention is that, it is possible that the Worker (child) thread could have cached the variable "value" of the Worker object thread-locally and updated just it's copy while setting the value to 1. In such a case, main thread may not see the updated value.

    You are correct. Even though you are both dealing with the same Worker instance, there is no guarantee that the cached memory version of the Worker's fields have been synchronized between the various different thread memory caches.

    The value field must be marked as volatile to guarantee that other threads will see the value = 1; update to the value field.

    But my teammate believes that since the access to "value" is happening through an object (worker), therefore for both the threads to see different values, it could only be possible if both the threads were maintaining separate copies of "worker" object itself...

    No, this is not correct. The tricky part about thread memory revolves around processor memory caches. Without a memory barrier that is imposed by volatile, a process is completely free to cache memory. So even though both threads would be working with the same instance of the Worker, they may have a locally cached copy of the memory associated with Worker.

    Thread architectures get much of their speed because they are working with separate high-speed processor-local memory as opposed to always referencing central storage.