Pure Danger Tech


navigation
home

JMM and final field freeze

26 Nov 2008

Internally, someone had this question yesterday: [source:java]

public SomeClass {

private final LinkedHashMap map = new LinkedHashMap();</p>

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…

}

[/source]

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!