Initializing non-final field Initializing non-final field multithreading multithreading

Initializing non-final field


This is called a "premature publishing" effect.

Putting it simple, JVM is allowed to reorder program instructions (for performance reasons), if such reordering does not violate the restrictions of JMM.

You expect the code f = new FinalFieldExample(); to run like:

1. create the instance of FinalFieldExample
2. assign 3 to x
3. assign 4 to y
4. assign created object to variable f

But in provided code, nothing can stop JVM from instruction reordering, so it can run the code like:

1. create the instance of FinalFieldExample
2. assign 3 to x
3. assign raw, not fully initialized object to variable f
4. assign 4 to y

If reordering happens in a single thread environment, we won't even notice it. That's because we expect, that objects will be fully created before we start to work with them and JVM respects our expectations. Now, what can happen, if several threads run this code simultaneously? In next example Thread1 is executing method writer() and Thread2 - method reader():

Thread 1: create the instance of FinalFieldExample
Thread 1: assign 3 to x
Thread 1: assign raw, not fully initialized object to variable f
Thread 2: reading f, it is not null
Thread 2: reading f.x, it is 3
Thread 2: reading f.y, it is still 0
Thread 1: assign 4 to y

Definitely not good. To prevent JVM doing this, we need to give it additional information about the program. For this particular example, there are some ways to fix the memory consistency:

  • declare y as final variable. This will cause "freeze" effect. In short, final variables will be always initialized on the moment when you access them, if reference to the object was not leaked during construction.
  • declare f as volatile variable. This will create "synchronization order" and fix the problem. In short, instructions can't be reordered below volatile write and above volatile read. Assigning to f variable is a volatile write, that means new FinalFieldExample() instructions can't be reordered and executed after assignment. Reading from f variable is a volatile read, so reading f.x can not be executed before it. Combination of v-write and v-read is called synchronization order and provides the desired memory consistency.

Here is a good blog, that can answer all your questions about JMM.


The JVM may reorder memory reads and writes, so the reference to f may be written to main memory before the value of f.y. If another thread reads f.y between these two writes, it will read 0. However, if you create a memory barrier by writing a final or volatile field, reads and writes after the barrier cannot be reordered with respect to reads and writes before the barrier. So it's guaranteed that both f and f.y will be written before another thread reads f.

I asked a similar question here. The answers go into a lot more detail.


Java memory model allows a thread to create a FinalFieldExample, initialize final x and save a reference to FinalFieldExample instance to f field before initializing non-final y.