Is Java's volatile keyword "recursive" regarding references tree, or must each reference be declared as volatile?

StackOverflow https://stackoverflow.com/questions/20802717

  •  22-09-2022
  •  | 
  •  

Question

Considering the following toy example class:

public class Test {

    private volatile Outer outerVar = new Outer();

    static class Outer {
        Inner innerVar = new Inner();
    }

    static class Inner {

        // state

        // setters

        // getters

    }

    private void multithreadedUse() {
        // play with outerVar.innerVar
    }
}

outerVar is volatile so all threads that may be using it will see it in the same state. But what about outerVar.innerVar? Does the fact that its parent object ( outerVar ) is marked as volatile make it volatile also?

Or do we have to declare innerVar volatile explicitly?

Was it helpful?

Solution

But what about outerVar.innerVar? Does the fact that its parent object ( outerVar ) is marked as volatile make it volatile also?

In this example outerVar.innerVar will be published correctly, but it will not be volatile. If you were to assign outerVar.innerVar = new Inner() as some later point you will lose the thread-safe publication.

The rule here is that all write that occur prior to a volatile write are visible after the volatile write. After that write, all normal writes are now thread-unsafe.

So in your example the ordering from a thread would see something similar to

volatile Outer outerVar;
Outer temp = new Outer();
temp.innerVal = new Inner()
outerVar = temp;

Notice the volatile write of outVar = temp. This is where the synchronization starts. And when another thread reads a non-null outerVar instance, the innerVar field will be safely published.

To reiterate though, any time you assign a new value to outerVar.innerVal you will lose synchornization. Similarly if innerVal has any field [after the initial volatile write] writes to those fields will not be correctly synchronized

So to answer your question

Is Java's volatile keyword “recursive” regarding references tree, or must each reference be declared as volatile?

Each field must be declared volatile that will change after the initial volatile write (technically speaking). That being said, you should declare fields either volatile or final if you are sharing among threads.

OTHER TIPS

your understanding of Volatile is correct and your expectation for it on Outer class object is also correct. However the properties of the Outer class are not immune to thread safety and that does defeat the purpose of volatile here. The best way to fix your situation is to make inner variable immutable. This is how volatile Boolean wrapper and Strings work. Making the inner state immutable and also final, makes your volatile object thread safe and thus can be used freely.

But still of you want to stick wit your code, then as long as you dont change the properties of the Outer class once instantiated, you are good. But thats essentially what final and immutability mean too.

Check out this link about basics of thread safety.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top