11

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.

Community
  • 1
  • 1
Archie
  • 4,959
  • 1
  • 30
  • 36
  • How about an `AtomicReference`? – Andy Turner Aug 08 '16 at 22:35
  • Could use use `@NonNull private Object value;` from Java 8? – 4castle Aug 08 '16 at 22:36
  • 1
    In which scenario the method `getValue()` in the first example could return `null` ? further, if you plan to assign a value only once in the constructor and then just read it - it sounds like you're looking for an immutable object, in that case - why not declare it as `final` ? (I see that you wrote "non-final" only that you didn't provide a good motivation...) – Nir Alfasi Aug 08 '16 at 22:40
  • 5
    `getValue()` can't return null unless there is a `this` escape from the constructor, which there isn't. Otherwise any call to `getValue()` must follow the entire constructor, either in the same thread or in a thread started by the same thread after the constructor returns, and [JLS #17.4;5](http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.4.5) guarantees *hb(x,y)* if *x* and *y* are successive actions in the same thread. – user207421 Aug 08 '16 at 22:41
  • 1
    If it's initialized in the constructor, and never changed, why not make it final? – Bohemian Aug 08 '16 at 22:46
  • @Bohemian There are situations where you can't make a field `final`, for example when you're implementing `Cloneable` and you need to deep clone some fields. – Archie Aug 08 '16 at 22:49
  • @EJP why _or in a thread started by the same thread after the construction returns_ ? Thread could have already started and a `this` reference given to it by the thread that invoked the constructor. – Archie Aug 08 '16 at 22:50
  • 2
    @Archie Quite right. But the `this` reference only exists after the constructor returns, and the action of giving it to another thread would constitute `y` in the terms of the JLS quotation. – user207421 Aug 08 '16 at 22:58
  • @EJP What's your source for that? – shmosel Aug 09 '16 at 00:28
  • The `this` reference can `escape` the constructor by being passed to a method called from within the constructor, meaning that the assignment to the `value` field may as well not be visible to another thread. But there is no such leak in the original question. – PNS Aug 09 '16 at 00:34
  • "such that no subsequent access of that field by any other thread can see a non-null value" - Did you mean "null value"? – Hulk Aug 09 '16 at 08:53
  • The idea is that some thread _T1_ invokes the `Holder` constructor, the constructor returns, and then _T1_ makes the new `Holder` object visible to some other thread _T2_, which then invokes `get()`; in this case `get()` could return `null` (only possible because the field is not `final`). – Archie Aug 09 '16 at 16:14
  • If that is true, then the explicit statement of the JVM specification that "An object is considered to be completely initialized when its constructor finishes" is not correct and is only applicable for final fields, as the next phrase in the same document implies. – PNS Aug 09 '16 at 18:17
  • Correct - that statement only applies to final fields. Therein lies the rub. – Archie Aug 09 '16 at 22:17

4 Answers4

6

To safely publish a non-immutable object in Java, You need to synchronise the construction of the object and the write of the shared reference to that object. It's not just the internals of that object that matters in this question.

If you publish an object without proper synchronisation, with reordering, the consumer of a Holder object can still see a partially constructed object if the reference to the object got published before the constructor finishes. For example Double-checked locking without volatile.

There are several ways to publish an object safely:

  • Initialising a 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; Or
  • Storing a reference to it into a field that is properly guarded by a lock.

Note that those bullet points are talking about the reference to the Holder object, not fields of the class.

So the easiest way would be the first option:

public static Holder holder = new Holder("Some value");

Any thread accessing the static field is going to see a properly constructed Holder object.

See Section 3.5.3 "Safe publication idioms" of Java Concurrency in Practice. For more information about unsafe publication, see Section 16.2.1 of Java Concurrency in Practice.

xiaofeng.li
  • 8,237
  • 2
  • 23
  • 30
  • Good call. Safe publication is the way to guarantee the field is set. Without safe publication of `Holder`, even `synchronized` will not ensure visibility of its field; if `volatile` is insufficient, so is `synchronized`. On the other hand, if `Holder` is safely published, and effectively immutable, the field doesn't need any special treatment. – erickson Aug 09 '16 at 04:01
5

The problem you are trying to solve is called safe publication and there exist benchmarks for a best performant solution. Personally, I prefer the holder pattern which also performs the best. Define a Publisher class with a single generic field:

class Publisher<T> {
  private final T value;
  private Publisher(T value) { this.value = value; }
  public static <S> S publish(S value) { return new Publisher<S>(value).value; }
}

You can now create your instance via:

Holder holder = Publisher.publish(new Holder(value));

Since your Holder is dereferenced via a final field, it is guaranteed to be fully initialized by the JMM after reading it from the same final field.

If this is the only usage of your class, then you should of course add a convenience factory to your class and make the constructor itself private to avoid unsafe construction.

Note that this performs very well as modern VMs erase the object allocation after applying escape anaysis. The minimal performance overhead comes from the remaining memory barriers in the generated machine code which are however required to safely publish the instance.

Note: The holder pattern is not to be confused with your example class being called Holder. It is the Publisher that implements the holder pattern in my example.

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192
  • Pretty sure this doesn't work, for the same reason `volatile Holder v; Holder holder = v = new Holder(value);` wouldn't. It's meaningless to create a *happens-before* relationship between actions in a single thread because it already exists implicitly. It only works if the other thread actually reads from the `final` or `volatile` variable, as in the example you linked to. – shmosel Apr 10 '18 at 05:26
2

See section 17.5 of the Java Language Specification.

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.

In other words, as long as we are careful not to leak this from the constructor of Holder to another thread, we can guarantee that other threads will see the proper (non-null) value of ref without additional synchronization mechanisms.

class Holder {

  private final Object ref;

  Holder(final Object obj) {
    if (obj == null) {
      throw new NullPointerException();
    }
    ref = obj;
  }

  Object get() {
    return ref;
  }
}

If you're seeking a non-final field, recognize we can use synchronized to enforce that get does not return until ref is non-null and also ensure a proper happens-before relationship (see: memory barrier) holds on the wrapped reference:

class Holder {

  private Object ref;

  Holder(final Object obj) {
    if (obj == null) {
      throw new NullPointerException();
    }
    synchronized (this) {
      ref = obj;
      notifyAll();
    }
  }

  synchronized Object get() {
    while (ref == null) {
      try {
        wait();
      } catch (final InterruptedException ex) { }
    }
    return ref;
  }
}
obataku
  • 29,212
  • 3
  • 44
  • 57
  • 3
    The question explicitly states "a Java class containing a **non-final** reference field", so saying that it works for final fields is not an answer to the question. Even the title says "non-final reference field". This, to me, means that OP is aware that it works for final fields, but is asking how to make it work for non-final fields. As such, this answer is not useful. – Andreas Aug 08 '16 at 23:38
  • 1
    This should work. But I doubt anyone actually write classes this way in real life. – xiaofeng.li Aug 09 '16 at 03:40
  • @LukeLee care to clarify? – obataku Aug 09 '16 at 03:49
  • IMHO It just costs too much. But for what? So that the user of this class will be able to not follow safe publication practice? – xiaofeng.li Aug 09 '16 at 03:56
0

It is not possible to guarantee that a non-final reference will never be null.

Even if you initialize it correctly and guarantee not null in the setter, it is still possible to set the reference to null via reflection.

You can limit the chances of returning a null reference by declaring the getter to be final and never returning null from the getter.

It is; however, still possible to override the final getter and force it to return null. Here is a link that describes how to mock a final method: Final method mocking

If they can mock a final method, anybody can, using the same technique, override a final method and make it function poorly.

Community
  • 1
  • 1
DwB
  • 37,124
  • 11
  • 56
  • 82
  • 3
    One can also change the value of a final instance field with reflection, but there is no such use case in the original question. – PNS Aug 08 '16 at 23:10
  • 1
    This question is not about hacking the object, but about multi-threaded access to the object. – Andreas Aug 08 '16 at 23:42
  • That's what I said, too: there is no such use case in the original question. I was just adding a bit more information on reflection vs. the final modifier, given the above answer. – PNS Aug 09 '16 at 00:25