26

From the book Java concurrency in practice :

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

  • Storing a reference to it into a field that is properly guarded by a
    lock.

My questions are :

  1. What are the the differences between bullet points 2 and 3 ? I am interested in the difference between volatile approach and final approach in terms of safe publication of the object .
  2. What does he mean by final field of a properly constructed object in point 3 ? Before starting the bulleted points authors already mentioned that they are talking about a properly constructed object (which I assume is not letting the this reference to escape ). But once again why did they mention about properly constructed objects ?
Geek
  • 26,489
  • 43
  • 149
  • 227

2 Answers2

18

What are the the differences between bullet points 2 and 3 ?

  • volatile basically means that any writes to that field will be visible from other threads. So when you declare a field as volatile: private volatile SomeType field;, you are guaranteed that if the constructor writes to that field: field = new SomeType();, this assignment will be visible by other threads that subsequently try to read field.
  • final has quite similar semantics: you have the guarantee that if you have a final field: private final SomeType field; the write to that field (either in the declaration or in the constructor): field = new SomeType(); won't be reodered and will be visible by other threads if the object is properly published (i.e. no escape of this for example).

Obviously, the main different is that if the field is final, you can only assign it once.

What does he mean by final field of a properly constructed object in point 3 ?

If, for example, you let this escape from the constructor, the guarantee provided by the final semantics is gone: an observing thread might see the field with its default value (null for an Object). If the object is properly constructed this can't happen.


Contrived example:

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();
    }
}
assylias
  • 321,522
  • 82
  • 660
  • 783
  • 2
    If after construction I change the state of the object refered to by field like `field.setX(new X())`, is that change also guaranteeed to be seen by other threads when we declare it as volatile ? Or does it only give the initialization safety ? What about final in this case ? – Geek Feb 10 '13 at 04:36
  • 1
    No, only `field` gives you visibility guarantee on (re-)assignement. Unless `x` is also volatile, `field.x = new X();` (or your setter example) provides no such guarantee. – assylias Feb 10 '13 at 07:48
  • Same goes for final, with the corollary that if all the members of `field` are final too and are immutable, `field` is immutable and is therefore thread safe. – assylias Feb 10 '13 at 07:49
  • @assylias I read your answer a few times but still couldn't get it. Since field is final, there won't be any reordering, why would new thread won't see "field" attribute of "this"? Are you saying, it's because constructor isn't completed yet? – Abidi Sep 09 '13 at 08:53
  • You even have more guarantees when using `final` fields: "[The other thread] will also see versions of any object or array referenced by those final fields that are at least as up-to-date as the final fields are." ([source](https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.5)) – Marcono1234 May 03 '19 at 08:51
2

There is no difference in what the effects of publishing volatile vs final, except that final can only be set once in the constructor, and thus what you read should never change.

I believe a properly constructed object is indeed what you refer to, an object whose this reference did not escape its constructor and has been published in a safe manner to the thread that it is used in.

Steven Schlansker
  • 37,580
  • 14
  • 81
  • 100