Jason Law
Jason Law

Reputation: 1015

Why are both "Storing a reference to it into a final field" and "of a properly constructed object" needed in order to publish an object safely?

I'm reading "Java concurrency in practice", and it says:

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

What I don't understand is "Storing a reference to it into a final field of a properly constructed object", Why is "of a properly constructed object" needed? Without "of a properly constructed object", can other threads see the object that is being published in an inconsistent state?

I have read several related questions:

But I can't find much explanation about Why "of a properly constructed object" is needed.

Below example comes from an answer in question "final vs volatile guaranntee w.rt to safe publication of objects - Stack Overflow"

class SomeClass{
    private final SomeType field;

    SomeClass() {
        new Thread(new Runnable() {
            public void run() {
                SomeType copy = field; //copy could be null
                copy.doSomething(); //could throw NullPointerException
            }
        }).start();
        field = new SomeType();
    }
}

SomeClass is not properly constructed, of course, copy could be null, but in my opinion, the thread can not see the copy in an inconsistent state, either copy is null or "both the reference to the copy and the copy's state must be made visible to the threads at the same time". So, field is published safely even though SomeClass is not properly constructed. Am I right?

Hope someone can give me more explanation, thanks in advance.

Upvotes: 1

Views: 188

Answers (1)

JimmyB
JimmyB

Reputation: 12630

It depends on what you call "consistent state". If seeing a null pointer where a published object should be, i.e. the object actually looks as if it was not published, counts as "consistent" then you're right in that the example produces "consistency".

Do note however that final fields are supposed to not change their value. If a thread reads from a final it can safely assume that the field's value will not change later. The thread's implementation, or the (JIT) compiler, may 'cache' the field's value in some variable (or register) because final tells it that the value read once stays the same.

Specifically, code like

new Thread(new Runnable() {
    public void run() {
        while ( field == null ) {
          // Wait a little...
        }
        // Field was initialized, go ahead.
    }
}).start();

Will probably only have two possible outcomes: Either the loop is never entered, or it becomes an infinite loop.

That's why it is especially not safe to access a final field before it is initialized; and final fields are only guaranteed to be initialized after the constructor completed.

The issue may become more apparent if you write the fully qualified field name in the thread's code, which is SomeClass.this.field. You are allowed to omit it but the compiler will implicitly generate the proper access for you. Using the fully qualified field name you can see more clearly that the thread accesses SomeClass.this.field before this is fully initialized. So, effectively, you don't actually publish the consistent SomeType object but the still inconsistent SomeClass object which happens to contain that field.

Upvotes: 0

Related Questions