Volatile guarantee safe publication of a mutable object?
Asked Answered
A

3

11

By reading Java Concurrency in Practice

I can see:

To publish an object safely, both the reference to the object and the object's state must be made visible to other threads at the same time. A properly constructed object can be safely published by:

  • Initializing an object reference from a static initializer
  • Storing a reference to it into a volatile field or AtomicReference
  • Storing a reference to it into a final field of a properly constructed object
  • Storing a reference to it into a field that is properly guarded by a lock.

However, I am confused about the second idiom. Since volatile can only guarantee that the reference is visible to another thread but it doesn't have synchronization of object construction which it refers to. So how can it guarantee that the mutable object is properly constructed, what is the thread that is constructing this object is interrupted by another thread?

Athletics answered 18/10, 2016 at 21:59 Comment(0)
G
13

We need to show that constructing an object and assigning it to a volatile variable happens before it is read from that variable.

From JLS Chapter 17:

If x and y are actions of the same thread and x comes before y in program order, then hb(x, y).

So, construction of an object happens before it is assigned to a volatile variable, from the point of view of that thread.

If an action x synchronizes-with a following action y, then we also have hb(x, y).

And:

If hb(x, y) and hb(y, z), then hb(x, z).

If we could show that writing the volatile variable (action y) synchronizes-with reading the variable (action z), we could use the transitivity of happens-before to show that constructing the object (action x) happens-before reading the object. Luckily:

A write to a volatile variable v (§8.3.1.4) synchronizes-with all subsequent reads of v by any thread (where "subsequent" is defined according to the synchronization order).

Therefore, we can see that a properly constructed object is visible to any thread when published this way.

Gumshoe answered 18/10, 2016 at 22:26 Comment(5)
Thanks for your answer and it clearly answer my question. Btw, from what I understand, "final" key word can also have guaranteed this, but why is that so ? I assume the mechanism behind it is different ?Athletics
@GuifanLi The mechanism is different, and it explained in JLS 17.5. But I think the key part is this: "An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object after that object has been completely initialized is guaranteed to see the correctly initialized values for that object's final fields." So, make sure the the constructor of the object with final fields doesn't leak a reference to this, and nothing can see the object until it's completely initialized. That provides visibility.Gumshoe
Great explanation. But I have one more question. The program order rule is defined as partial ordering. In that case still the JVM has the liberty of changing the order in which x and y appears. How can we guarantee that it does not happen.Overlap
@RavindraRanwala It’s a partial ordering because it is only constrained to present the appearance of program order to other threads that synchronize with it. In this case, reading the volatile variable synchronizes with the write to the variable. Any change in execution that would be detectable by such a reader is not permissible.Gumshoe
@Gumshoe So that implies, the read is performed when the write is completed. Therefore despite the order in which write occurs i.e. either X -> Y or Y -> X, still the reader sees the same final result which is consistent. Great, now I get the point. Thanks a lot !Overlap
T
2

Reads and writes are atomic for all variables declared volatile (including long and double variables).

Consequence: volatile guarantees, among others, that the variable is always read from the memory shared by all threads - if the value is published in a volatile variable, it must be fully constructed before.
In other words, if a volatile value is not published, then no other threads will know about it - most probably the result of 'construction in progress' may reside in the CPU cache or in the memory that JVM uses as "space I'm using for my own purposes; you puny Java code, don't ask what's in it, it's not your business".

Twelvetone answered 18/10, 2016 at 22:26 Comment(2)
What about if the variable is a reference to an array? for example, volatile int[] arr = new int[5]. I know arr will be published safely, how about after publication, I make arr[0] = 100. Is this thread safe ? My point is that does this guarantee a safe publication of arr[0] = 100?Athletics
@GuifanLi The way I know/understand, there's no warranty for the content of the created instance (or array) after the publication. I might be wrong, though (and a bit busy for the moment to search for an answer).Twelvetone
K
1

volatile can only guarantee that the reference is visible to another thread but it doesn't have synchronization of object construction which it refers to.

Yes. You are right. You can find more details of internals about volatile variables in below question:

Difference between volatile and synchronized in Java

So how can it guarantee that the mutable object is properly constructed, what is the thread that is constructing this object is interrupted by another thread?

You have to use other programming constructs for thread safety : Using synchronized constructs or alternatives of synchronized constructs.

Refer to below related SE question:

Avoid synchronized(this) in Java?

Kampong answered 19/10, 2016 at 3:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.