Improper publication of Java Object Reference

concurrency, java

Solution

You can imagine creation of an object has a number of non-atomic functions. First you want to initialize and publish Holder. But you also need to initialize all the private member fields and publish them.

Well, the JMM has no rules for the write and publication of the `holder`'s member fields to happen before the write of the `holder` field as occurring in `initialize()`. What that means is that even though `holder` is not null, it is legal for the member fields to not yet be visible to other threads.

You may end up seeing something like

public class Holder {
    String someString = "foo";
    int someInt = 10;
}

`holder` may not be null but `someString` could be null and `someInt` could be 0.

Under an x86 architecture this is, from what I know, impossible to happen but may not be the case in others.

So next question may be "Why does volatile fix this?" The JMM says that all writes that happen prior to the volatile store are visible to all subsequent threads of the volatile field.

So if `holder` is volatile and you see `holder` is not null, based on volatile rules, all of the fields would be initialized.

To safely publish this object, do we have to make holder initialization static and declare it as volatile

Yes, because as I mentioned if the `holder` variable is not null then all writes would be visible.

How can the `AssertionError` be thrown?

If a thread notices `holder` not to be null, and invokes `AssertionError` upon entering the method and reading `n` the first time may be `0` (the default value), the second read of `n` may now see the write from the first thread.

Problem

The below example is from the book "Java Concurrency in Practice" by Brian Goetz, Chapter 3, Section 3.5.1. This is an example of Improper publication of objects: ``` class SomeClass { public Holder holder; public void initialize() { holder = new Holder(42); } } public class Holder { private int n; public Holder(int n) { this.n = n; } public void assertSanity() { if (n != n) throw new AssertionError("This statement is false"); } } ``` It says that the Holder could appear to another thread in an inconsistent state and another thread could observe a partially constructed object. How can this happen? Could you give a scenario using the above example? Also it goes on to say that there are cases when a thread may see a stale value the first time it reads a field and then a more up to date value the next time, which is why the `assertSanity` can throw `AssertionError`. How can the `AssertionError` be thrown? From further reading, one way to fix this problem is to make `Holder` immutable by making the variable `n` final. For now, let us assume that `Holder` is not immutable but effectively immutable. To safely publish this object, do we have to make holder initialization static and declare it as volatile (both static initialization and volatile or just volatile)? Something like this: ``` public class SomeClass { public static volatile Holder holder = new Holder(42); } ```

Original source

Related problems