Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 750
adragomir Avatar asked Dec 27 '13 14:12

adragomir


People also ask

How volatile will work if we have multiple threads writing to a volatile variable?

If you write volatile variable from multiple threads without using any synchronized constructs, you are bound to get data inconsistency errors. Use volatile variables without synchronization in case of single write thread and multiple read threads for atomic operations.

What is the use of volatile keyword when should we use volatile variable in Java?

Volatile keyword is used to modify the value of a variable by different threads. It is also used to make classes thread safe. It means that multiple threads can use a method and instance of the classes at the same time without any problem. The volatile keyword can be used either with primitive type or objects.

Does declaring a variable as volatile ensures thread safety?

Unlike synchronized methods or blocks, it does not make other threads wait while one thread is working on a critical section. Therefore, the volatile keyword does not provide thread safety when non-atomic operations or composite operations are performed on shared variables.

What will happen if we declare the variable as volatile in Java?

Volatile variables have the visibility features of synchronized but not the atomicity features. The values of the volatile variable will never be cached and all writes and reads will be done to and from the main memory.


1 Answers

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.

like image 183
John Vint Avatar answered Oct 29 '22 06:10

John Vint