JMM and final field freeze

11

Internally, someone had this question yesterday:

public SomeClass {
private final LinkedHashMap map = new LinkedHashMap();

public SomeClass() {
init();
}

private void init() {
// just create objects and map.put() –
// no tricks here, no this escaping, etc
}

// A read method
public Object get(Object key) {
return map.get(key);
}

// etc…
}

And the question is:

The map is never mutated after construction. The field is declared final. Are the read methods thread-safe and guaranteed to show you the map with all values? If not, is an additional memory barrier required to guarantee this?

I think pretty much everyone agreed that readers are guaranteed to see the map instance but there was some question about whether the puts to the map during init() can be reordered such that they are not thread-safe with respect to the get()s.

After many folks weighed in, the consensus is that yes, the reads are definitely thread-safe even in the absence of an additional memory barrier.

One goal of JSR 133 (which defines the Java Memory Model) is to preserve initialization safety. The JSR 133 FAQ says:

If an object is properly constructed (which means that references to it do not escape during construction), then all threads which see a reference to that object will also see the values for its final fields that were set in the constructor, without the need for synchronization.

I think that’s a pretty good summary of the intent. The concept of whether changes to final fields are visible at end of construction is explicitly talked about in the memory model semantics paper as well in the section on “informal semantics of final fields”:

F1 When a final field is read, the value read is the value assigned in the constructor.

F2 Assume thread T1 assigns a value to a final field f of ob ject X defined in class C. Assume that T1 does not allow any other thread to load a reference to X until after the C constructor for X has terminated. Thread T2 then reads field f of X. Any writes done by T1 before the class C constructor for ob ject X terminates are guaranteed to be ordered before and visible to any
reads done by T2 that are derived from the read of f.

Java Concurrency in Practice also mentions this in section 16.3:

Initialization safety guarantees that for *properly constructed* objects, all threads will see the correct values of final fields that were set by the constructor, regardless of how the object is published. Further, any variables that can be *reached* through a final field of a properly constructed object (such as the elements of a final array or the contents of a HashMap referenced by a final field) are also guaranteed to be visible to other threads.

For objects with final fields, initialization safety prohibits reordering any part of construction with the initial load of a reference to that object. All writes to final fields made by the constructor, as well as to any variables reachable through those fields, become “frozen” when the constructor completes, and any thread that obtains a reference to that object is guaranteed to see a value that is at least as up to date as the frozen value. Writes that initialize variables reachable through final fields are not reordered with operations following the post-construction freeze.

I find the formal definition of the final field freeze semantics to be fairly impenetrable, so I’ll just trust that they say formally what is stated informally above.

Final fields are ever so important and useful. Whenever possible, strive to make your fields final. One tip for this is to enable a Save Action in Eclipse (or your IDE of choice) that automatically attempts to make fields final if possible so you can’t forget!

Comments

11 Responses to “JMM and final field freeze”
  1. Tim Jansen says:

    I would disagree and say that the reads are not thread-safe. The field someClass.map will be visible, of course. But LinkedHashMap itself is not thread-safe and has non-final fields. Thus any writes to those fields may be not visible in other threads. Writing to a final field is no memory barrier (at least in the JMM, in real-world implementations it may be).

    In the quotes that you posted I can’t find anything about writes to final members influencing the visibility of writes to non-finals. It’s just about the visibility of finals: a final member is only visible to other threads after the completion of the constructor. (someClass.map is visible in init() anyway, because init() runs in the same thread)

    The JLS offers a very simple summary of the JMM:
    * An unlock on a monitor happens-before every subsequent lock on that monitor.
    * A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.
    * A call to start() on a thread happens-before any actions in the started thread.
    * All actions in a thread happen-before any other thread successfully returns from a join() on that thread.
    * The default initialization of any object happens-before any other actions (other than default-writes) of a program.

    It’s even simpler if you ignore the points 3 and 4, which are not that interesting most of the time.

  2. Alex says:

    Well, I’m pretty sure I’m right, but then I’ve learned to never fully trust my understanding of the JMM. Regarding the quotes, the JCIP quote specifically gives an example of the contents of a final Map being visible after construction.

    If you continue reading down the page on that JLS reference you gave, you’ll come to the section on final fields (17.5) which gives much weight to my argument. Quotes like:

    “Final fields also allow programmers to implement thread-safe immutable objects without synchronization. A thread-safe immutable object is seen as immutable by all threads, even if a data race is used to pass references to the immutable object between threads.”

    “Set the final fields for an object in that object’s constructor. Do not write a reference to the object being constructed in a place where another thread can see it before the object’s constructor is finished. If this is followed, then when the object is seen by another thread, that thread will always see the correctly constructed version of that object’s final fields. It 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.”

    That seems very clear to me. Happens before is great but it is NOT sufficient (according to the JLS page you referenced) to define proper behavior. The actual JMM takes other things into account.

  3. I agree with Alex.

    But even without the final it would be ‘threadsafe’. Eventually the object needs to be published to make the reference visible to other threads. This publication is going to introduce a happens before relation between the initialization of the hashmap and the usage of the hashmap because the happens before rules are transitive.

    http://pveentjer.wordpress.com/2008/04/02/jmm-constructors-dont-have-visiblity-problems/

    But using finals is better, you don’t need to depend on an external environment to resolve the issues. And making stuff final also is a good form of documentation.

  4. It really depends on the reference to the SomeClass instance. Is *that* safely published (i.e. in a final field) to all threads? If yes then it’s fine, whatever you put in init() will be visible in other threads calling get().

    As Peter correctly points out you don’t even need to declare the map field final for it to be threadsafe, and “effectively” immutable (since it is never written to after init()).

    Dhanji.

  5. Brian Goetz says:

    Alex is correct, but it is not surprising that this is confusing enough to get different answers — this is deliberately exploring the boundaries of the memory model.

    One unstated assumption is that the keys and values in the map are individually thread-safe or effectively immutable.

    I don’t buy Peter’s argument, though. While the elements of the map may eventually “become visible” without final, it may be seen to violate some obvious invariants in the absence of the final or other ordering guarantees. For example, you could iterate the keys of the LHM but have containsKey() return false for one of those keys. That would clearly be confusing.

  6. Hi Brian,

    I think you have overlooked a part of my argument or I didn’t express myself clearly, because a safe publication need some kind of synchronization action like a volatile or a lock for example.

    If an object has publication problems (all fields are normal and not volatile/final/used in a synchronized context) the object can be safely used in a multithreaded environment if:
    -in some point in time this object is published correctly by using volatile/final/synchronized context and not before
    - the object is not changed after this publication

    The ordering gurantees for the volatile write/synchronized unlock are so strong that instruction before them can’t jump over them, so constructor code for example is not allowed to be executed after this publication, The same goes for the ordering gurantees of the volatile read/synchroned lock: the ordering guarantees are so strong that instructions that come after them can’t jump in front of them.

    In your book have written a small chapter about it: piggybacking on synchronization. And I think it is one of the most powerfull features of the new JMM (since objects with publication problems can be used safely, for example by using a blockingqueue or concurrentmap).

    Occording to the JMM in the case of the SomeClass (without final map):
    1) there is a happens before relation between the creation of the someclass and the publication (using a volatile variable for example) : program order rule
    2) there is a happens before relation between the write and read of a volatile variable (volatile variable rule)
    3) there is a happens before relation between the read of the volatile variable, and the usage of the internals

    And since the happens before rules are transitive, there is a happens before relation between action1 and action3.
    So the SomeClass can safely be used in a multithreaded environment if it is published safely (and not changed after construction).

    If I got this wrong, it would mean that there is a serious holes in my understanding of the JMM and I would like to understand what I’m missing.

  7. Tim Jansen says:

    You are right, the objects reachable by a final field have the same visibilty as the final field itself. I didnt know that.

  8. Brian Goetz says:

    Peter, are you assuming that the SomeClass object is itself safely published? You didn’t state that assumption. If so, though, this is right, as the state of the SomeClass *is* the state of the Map.

  9. Yoav Zibin says:

    At first I agreed with Tim Jansen, that LinkedHashMap does not use a final field, and therefore is not thread-safe without using synchronization.
    But after actually reading the original JSR133 spec, I saw
    Figure 22: Transitive guarantees from final fields
    and it shows this exact example.
    So I agree with Alex, and it is thread safe.

  10. miluch says:

    @Brian

    If we assume that keys and values in map are individually effectively immutable/immutable we can surely say that SomeClass is immutable. With regard to your answer to Peter Veentjer comment how come that immutable object is not published safely ? What i do understand from your book is that immutable objects are always safely published…

    If an object is immutable that it can be safely published through any mechanism (according to your book). By any mechanism i understand any approach to make an instance of SomeClass visible to other thread, e.g storing an instance of SomeClass in some public field of other class instance.

  11. Peter Firmstone says:

    Be careful with other people’s code.

    java.security.Permission objects are intended to be immutable like String, however the getAction() method states that generation of the action String may be delayed.

    We stored SocketPermission objects in a TreeSet that was wrapped in a Collections.unmodifiableSet, referenced by a final field.

    We experienced data races, where the SocketPermission didn’t imply another identical instance of SocketPermission when it clearly should have.

    We fixed the issue by using a ConcurrentSkipListSet instead of TreeSet and calling Permission.getAction() on every permission object prior to adding to the collection.

    This Set was never modified after construction, however SocketPermission performed some internal mutations that were inconsistent between threads, enough for the implies call to fail.

    Is it just me or is a volatile reference or concurrent collection used for publishing to other threads, less susceptible to reordering than final?