Java Constructors and thread safety [closed] - java

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
Literature talks about advertising a reference to an object before its constructor finished allocating and initializing its data structures. This usually involves putting it somewhere where other threads can see it prematurely. As I understand it, it involves an explicit act of advertising such as when using a Listener.
My question relates to the implementation of a constructor and the possibility of something similar happening. I can imagine that a constructor can be implemented with something similar to:
Type t = new Type(...);
An implementation in C might do something like:
t = malloc(sizeOf Type);
And then proceed to initialize all the fields.
If it can be implemented like this, then the reference t will be non-null, before the data is initialized. If another thread checks it for being non-null, it will then proceed to use it before it is fully initialized. The result will be mayhem.
I cannot find anything that says that you cannot implement it like this. I am probably missing something pretty basic in my understanding of the Java Memory Model. Is there anything that instructs JVM implementors not to do it like this?

Every once in a while, the thread-safely of Java object constructors comes up. More specifically, it's not so much about the process of object construction but rather the visibility of writes triggered by that process in relation to other threads.
What if a JVM implementation were to allocate memory for the new instance, store the new reference value and only then execute the constructor? What are the guarantees provided by the Java memory model and would that represent a violation?
It's all about the actual reference assignment. Constructors themselves do not come with a guarantee that all writes happen before the write of the object reference. If the reference is not assigned to a volatile or final field, the JIT and/or the target CPU (in terms of memory reordering) are free to assign the reference before object construction. That's an optimization decision the JIT can easily make. In case of volatile or final fields, however, the situation is different as of Java 1.5.
A prominent example affected by constructor thread-safety is the double-checked locking pattern (lazy initialization not requiring a lock after the initialization phase), which, if implemented as follows, suffers from a concurrency issue and is not thread-safe. Another thread may see a partially constructed Singleton instance because the Java memory model does not mandate any specific memory ordering for normal reads and writes.
private Singleton singleton;
public Singleton getInstance() {
if (singleton == null) {
synchronized (this) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
With Java 1.5, the memory model was changed in respect to volatile and final fields. With the new model, volatile writes have release semantics and volatile reads have acquire semantics. Provided volatile is used for singleton, this pattern works as expected because the memory model guarantees the expected order of events.
tmp = new Singleton();
// implicit release memory barrier caused by volatile
singleton = tmp;
Release semantics prevent memory reordering of any read or write that precedes it in program order with any write that follows it in program order. This is equivalent to a combination of LoadStore and StoreStore memory barriers. Consequently, reads and writes belonging to Singleton object construction must not move after the volatile singleton write.
tmp = singleton;
// implicit acquire memory barrier caused by volatile
if (tmp == null) {
synchronized (this)
if (tmp == null) {
Acquire semantics prevent memory reordering of any read that precedes it in program order with any read or write that follows it in program order. This is equivalent to a combination of LoadLoad and LoadStore memory barriers. Consequently, Singleton reads and writes must not move before the volatile singleton read.
It's worth noting that in all versions of Java, volatile reads and writes are totally-ordered. All threads observe the same volatile read/write order. To achieve that, either a volatile write precedes a StoreLoad memory barrier or a volatile read follows a StoreLoad memory barrier. On x86, only the StoreLoad memory barrier emit and instruction, other barriers have to be considered during JIT reordering.
Similarly, the semantics in terms of final fields have changed with Java 1.5. JSR133, which introduced the memory model changes, used the following example to illustrate the problem:
class FinalFieldExample {
final int x;
int y;
static FinalFieldExample f;
public FinalFieldExample() {
x = 3;
y = 4;
}
static void writer() {
f = new FinalFieldExample();
}
static void reader() {
if (f != null) {
int i = f.x;
int j = f.y;
}
}
}
Given two threads, thread A calling writer() and thread B calling reader(), the natural assumption would be that thread B is guaranteed to see the values 3 for i and and 0 or 4 for j. Due to reordering, thread B could see 0 instead - a clear violation of the premise of final, not in terms of the original memory model but in respect to the higher-level contract of final to represent immutable constant values.
To address this, Java 1.5 and later specify this guarantee:
[...] 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. [...]
The implementation uses a StoreStore memory barrier to prevent the write of x from moving after the assignment of f. Default values of y can still be observed.
In Java 9, java.lang.invoke.VarHandle was introduced to provide access to acquire/release and volatile semantics. VarHandle is comparable to C++11's std::atomic in that it provides atomic primitives and memory ordering control including explicit memory barriers.
The Java object constructor is not inherently thread-safe. With the help of volatile, final, and VarHandle, required guarantees can be established. For most common use cases, alternative patterns exist that do not require dealing with these kinds of low-level details. Whenever possible, prefer not to roll your own lock-free code to reduce code complexity and maximize the probability of correctness.

A direct violation of your hypothetical implementation of an allocator is in JLS 17.5 which enforces that any seen references to an object see all its final fields correctly initialized: "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." The allocator you made would fail this invariant.

Related

Can a volatile variable that is never assigned null to ever contain null?

Can in the following conceptual Java example:
public class X implements Runnable {
public volatile Object x = new Object();
#Runnable
public void run() {
for (;;) {
Thread.sleep(1000);
x = new Object();
}
}
}
x ever be read as null from another thread?
Bonus: Do I need to declare it volatile (I do not really care about that value, it suffices that sometime in the future it will be the newly assigned value and never is null)
Technically, yes it can. That is the main reason for the original ConcurrentHashMap's readUnderLock. The javadoc even explains how:
Reads value field of an entry under lock. Called if value field ever appears to be null. This is possible only if a compiler happens to reorder a HashEntry initialization with its table assignment, which is legal under memory model but is not known to ever occur.
Since the HashEntry's value is volatile this type of reordering is legal on consturction.
Moral of the story is that all non-final initializations can race with object construction.
Edit:
#Nathan Hughes asked a valid question:
#John: in the OP's example wouldn't the construction have happened before the thread the runnable is passed into started? it would seem like that would impose a happens-before barrier subsequent to the field's initialization.
Doug Lea had a couple comments on this topic, the entire thread can be read here. He answered the comment:
But the issue is whether assignment of the new C instance to some other memory must occur after the volatile stores.
With the answer
Sorry for mis-remembering why I had treated this issue as basically settled:
Unless a JVM always pre-zeros memory (which usually not a good option), then
even if not explicitly initialized, volatile fields must be zeroed
in the constructor body, with a release fence before publication.
And so even though there are cases in which the JMM does not
strictly require mechanics preventing publication reordering
in constructors of classes with volatile fields, the only good
implementation choices for JVMs are either to use non-volatile writes
with a trailing release fence, or to perform each volatile write
with full fencing. Either way, there is no reordering with publication.
Unfortunately, programmers cannot rely on a spec to guarantee
it, at least until the JMM is revised.
And finished with:
Programmers do not expect that even though final fields are specifically
publication-safe, volatile fields are not always so.
For various implementation reasons, JVMs arrange that
volatile fields are publication safe anyway, at least in
cases we know about.
Actually updating the JMM/JLS to mandate this is not easy
(no small tweak that I know applies). But now is a good time
to be considering a full revision for JDK9.
In the mean time, it would make sense to further test
and validate JVMs as meeting this likely future spec.
This depends on how the X instance is published.
Suppose x is published unsafely, eg. through a non-volatile field
private X instance;
...
void someMethod() {
instance = new X();
}
Another thread accessing the instance field is allowed to see a reference value referring to an uninitialized X object (ie. where its constructor hasn't run yet). In such a case, its field x would have a value of null.
The above example translates to
temporaryReferenceOnStack = new memory for X // a reference to the instance
temporaryReferenceOnStack.<init> // call constructor
instance = temporaryReferenceOnStack;
But the language allows the following reordering
temporaryReferenceOnStack = new memory for X // a reference to the instance
instance = temporaryReferenceOnStack;
temporaryReferenceOnStack.<init> // call constructor
or directly
instance = new memory for X // a reference to the instance
instance.<init> // call constructor
In such a case, a thread is allowed to see the value of instance before the constructor is invoked to initialize the referenced object.
Now, how likely this is to happen in current JVMs? Eh, I couldn't come up with an MCVE.
Bonus: Do I need to declare it volatile (I do not really care about
that value, it suffices that sometime in the future it will be the
newly assigned value and never is null)
Publish the enclosing object safely. Or use a final AtomicReference field which you set.
No. The Java memory model guarantees that you will never seen x as null. x must always be the initial value it was assigned, or some subsequent value.
This actually works with any variable, not just volatile. What you are asking about is called "out of thin air values". C.f. Java Concurrency in Practice which talks about this concept in some length.
The other part of your question "Do I need to declare x as volatile:" given the context, yes, it should be either volatile or final. Either one provides safe publication for your object referenced by x. C.f. Safe Publication. Obviously, x can't be changed later if it's final.

Cost of using final fields

We know that making fields final is usually a good idea as we gain thread-safety and immutability which makes the code easier to reason about. I'm curious if there's an associated performance cost.
The Java Memory Model guarantees this final Field Semantics:
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.
This means that for a class like this
class X {
X(int a) {
this.a = a;
}
final int a;
static X instance;
}
whenever Thread 1 creates an instance like this
X.instance = new X(43);
while (true) doSomethingEventuallyEvictingCache();
and Thread 2 sees it
while (X.instance == null) {
doSomethingEventuallyEvictingCache();
}
System.out.println(X.instance.a);
it must print 43. Without the final modifier, the JIT or the CPU could reorder the stores (first store X.instance and then set a=43) and Thread 2 could see the default-initialized value and print 0 instead.
When JIT sees final it obviously refrains from reordering. But it also has to force the CPU to obey the order. Is there an associated performance penalty?
Is there an associated performance penalty?
If you take a look at the source code of the JIT compiler, you will find the following comment regarding final member variables in the file src/share/vm/opto/parse1.cpp:
This method (which must be a constructor by the rules of Java) wrote a final. The effects of all initializations must be committed to memory before any code after the constructor publishes the reference to the newly constructor object. Rather than wait for the publication, we simply block the writes here. Rather than put a barrier on only those writes which are required to complete, we force all writes to complete.
The compiler emits additional instructions if there are final member variables. Most likely, these additional instructions cause a performance penalty. But it's unclear, if this impact is significant for any application.

Double check locking and code reordering in Java [duplicate]

This question already has answers here:
Why is volatile used in double checked locking
(8 answers)
Closed 4 years ago.
In some article I read that double check locking is broken. As the compiler can reorder the sequence of constructors.
Ss allocate memory for an object
Then return the address to a reference variable
Then initialize the state of the object
While typically one would expect:
It should be as allocated memory for the object
then initialize the state of object
then return the address to the reference variable.
Again, when using the synchronized keyword, the code reorder never happens as per JMM specification.
Why is compiler reordering the sequence of constructor events when it is inside the synchronized() block?
I saw a lot of posts here about DCL, but I am expecting the description based on JMM and compiler reordering.
The compiler is free to reorder instructions within a synchronized block. And the compiler is free to reorder instructions before (as long as they stay before) or after (as long as they stay after) the synchronized block. However, the compiler is not free to reorder instructions across the synchronized block boundaries (block start or block end).
Thus, the construction and assignment which are wholly within the synchronized block can be reordered, and an outside viewer which has not correctly synchronized can see the assignment before the construction.
First of all:
Again when using the synchronized keyword, the code reorder never happens as per the JMM specification.
The above statement is not fully accurate. The JMM defined the happens-before relationship.
The JLS only defines the program order and happens-before order. See 17.4.5. Happens-before Order.
It has effects on the reordering of instructions. For example,
int x = 1;
synch(obj) {
y = 2;
}
int z = 3;
Now for the above piece of code, the below types of reordering are possible.
synch(obj) {
int x = 1;
y = 2;
int z = 3;
}
The above is a valid reordering.
See Roach Motels and The Java Memory Model.
synch(obj) {
int z = 3;
y = 2;
int x = 1;
}
The above is also a valid reordering.
What is not possible is that y=2 will only be executed after the lock has been acquired and before the lock is released this is what guaranteed given by JMM. Also to see the correct effects from another thread, we need to access y inside the synchronized block only.
Now I come to DCL.
See the code of DCL.
if (singleton == null)
synch(obj) {
if(singleton == null) {
singleton == new Singleton()
}
}
return singleton;
Now the problem in the above approach is:
singleton = new Singleton() is not a single instruction. But a set of instructions. It is quite possible that a singleton reference is assigned an object reference first, before fully initializing the constructor.
So if 1 happens then it's quite possible the other thread reads a singleton reference as a non null and thus is seeing a partially constructed object.
The above effects can be controlled by making a singleton as volatile which also establishes happens-before guarantees and visibility.
Why is compiler reordering the sequence of constructor events when it is inside the synchronized() block?
It would typically do this to make the code run faster.
The Java Language Specification (JLS) says that the implementation (for example, the compiler) is allowed to reorder instructions and sequences of instructions subject to certain constraints.
The problem is that the broken variants of DCL make assumptions that fall outside of what the JLS says can be made. The result is an execution that the JLS says is not well-formed. Whether this manifests itself as an actual bug / unexpected behaviour depends on the compiler version, the hardware and various other things.
But the point is that the compiler isn't doing anything wrong. The fault is in the DCL code.
I just want to add that the JIT compiler is often not reordering the events per se. what it is often doing is removing constraints on hardware-level memory read/write actions. For example, by removing the constraint that a particular memory write is flushed to main memory, you allow the hardware to defer (or even skip entirely) a slow write-to-memory, and just write to the L1 cache. By contrast, the end of a synchronized block will force the cached writes to main memory, incurring extra memory traffic and (probably) a pipeline stalls.

Java double-checked locking solution?

This is a followup from Java double checked locking.
The following code snippet has 2 interesting characteristics.
1) It requires a call to a separate init() method before the object is ready for use. So volatile doesn't help (I know, why don't I just put the code in init() into the constructor? It's here for the purposes of illustration).
2) It uses a tmp variable to do the initialization and assigns to instance after initialization is complete.
if (instance == null) {
synchronized (mutex) {
if (instance == null) {
AClass tmpInstance = new AClass();
tmpInstance.init();
instance = tmpInstance;
}
}
}
So, is this subject to the reordering problem, i.e., could instance be assigned to tmpInstance prior to tmpInstance.init() being called?
Thanks,
Rich
All that matters is that you are assigning to instance as the last operation, after all initialization is done. Since instance is (hopefully) volatile, this will ensure all initialization is visible to later readers.
BTW there is really no need for you to learn all the rules of allowed reorderings: that's compulsory reading only for JIT compiler implementors.
All you, as a Java programmer, need to keep in mind are the two simple guarantees that the Java Memory Model offers you (one is about synchronized, the other about volatile). The whole point of the JMM rewrite (as of JLS 3) was to allow us to program against a very simple concurrency model.
So, is this subject to the reordering problem, i.e., could instance be
assigned to tmpInstance prior to tmpInstance.init() being called?
No but it is subject to the visibility problem which volatile does solve. So you should still declare instance volatile.
Now the reason why it is not subject to a reordering. Normal stores cannot be reordered after a monitor enter.
http://g.oswego.edu/dl/jmm/cookbook.html
1st Operation: MonitorEnter
2nd Operation: NormalStore
Can Reorder: No

Java memory barriers

I'm reading JSR 133 Cookbook and have the following question about memory barriers. An example of inserted memory barriers is in the book, but only writing and reading from local variables is used. Suppose I have the following variables
int a;
volatile int b;
And the code
b=a;
Do I understand correctly that this one line would produce the following instructions
load a
LoadStore membar
store b
The underlying behavior of the JVM is guaranteed only against the volatile variable. It may be possible that two separate threads may have access to different values for variable 'a' even after a thread completes evaluation of the b = a; statement. The JVM only guarantees that access to the volatile variable is serialized and has Happens-Before semantics. What this means is that the result of executing b = a; on two different threads (in the face of a "volatile" value for 'a' (ha ha)) is indeterminate because the JVM only says that the store to 'b' is serialized, it puts no guarantee on which thread has precedence.
More precisely what this means is that the JVM treats variable 'b' as having its own lock; allowing only one thread to read or write 'b' at a time; and this lock only protects access to 'b' and nothing else.
Now, this means different things under different JVMs and how this lock is actually implemented on different machine architectures may result in vastly different runtime behavior for your application. The only guarantee you should trust is what the Java reference manual says, "A field may be declared volatile, in which case the Java Memory Model ensures that all threads see a consistent value for the variable." For further review see Dennis Byrne's excellent article for some examples of how different JVM implementations deal with this issue.
Happens-Before semantics are not very interesting in the provided example because an integer primitive doesn't provide much opportunity for the kind of instruction reordering that volatile was intended (in part) to remedy. A better example is this:
private AnObjectWithAComplicatedConstructor _sampleA;
private volatile AnObjectWithAComplicatedConstructor _sampleB;
public void getSampleA() {
if (_sampleA == null) {
_sampleA = new AnObjectWithAComplicatedConstructor();
}
return _sampleA;
}
public void getSampleB() {
if (_sampleB == null) {
_sampleB = new AnObjectWithAComplicatedConstructor();
}
return _sampleB;
}
In this example field '_sampleA' has a serious problem; in a multithreaded situation it is very possible that '_sampleA' may be in the process of being initialized in one thread at the same time another thread attempts to use it leading to all sorts of sporatic and very, very difficult to duplicate bugs. To see this consider thread X to execute the 'new' byte code instruction statement of the new in getSampleA() and then stores the (yet-to-be-initialized) result in field '_sampleA'. Thread X is now paused by the JVM and thread Y starts executing getSampleA() and sees that the '_sampleA' is not null; which uninitialized value is then returned and thread Y now starts calling methods on the resulting instance causing all sorts of problems; which will, of course, only appear in production, at odd hours, and under heavy service loads.
The worse case for field _sampleB is that it may have multiple threads initializing individual instances; all but one of which will eventually be discarded. Code like this should be wrapped in a "synchronized" block but the volatile keyword will do the trick because it requires that the value finally stored in '_sampleB' has Happens-Before semantics which means that the stuff to the right of the equals sign is guaranteed to be complete when the stuff on the left hand side of the equals sign is performed.

Categories

Resources