I'm trying to solve a simple problem and am falling into a Java Memory Model rabbit hole.
What is the simplest and/or most efficient (judgement call here), but race-free (precisely defined according to the JMM) way to write a Java class containing a non-final reference field which is initialized to a non-null value in the constructor and subsequently never changed, such that no subsequent access of that field by any other thread can see a non-null value?
Broken starting example:
public class Holder {
private Object value;
public Holder(Object value) {
if (value == null)
throw NullPointerException();
this.value = value;
}
public Object getValue() { // this could return null!
return this.value;
}
}
And according to this post, marking the field volatile
doesn't even work!
public class Holder {
private volatile Object value;
public Holder(Object value) {
if (value == null)
throw NullPointerException();
this.value = value;
}
public Object getValue() { // this STILL could return null!!
return this.value;
}
}
Is this the best we can do??
public class Holder {
private Object value;
public Holder(Object value) {
if (value == null)
throw NullPointerException();
synchronized (this) {
this.value = value;
}
}
public synchronized Object getValue() {
return this.value;
}
}
OK what about this?
public class Holder {
private Object value;
public Holder(Object value) {
if (value == null)
throw NullPointerException();
this.value = value;
synchronized (this) { }
}
public synchronized Object getValue() {
return this.value;
}
}
Side note: a related question asks how to do this without using any volatile
or synchronization, which is of course impossible.