Search code examples
javamultithreadingconcurrencyfinaljava-memory-model

final Fields In The Java Memory Model


Could you explain how the value of f.y could be seen 0 instead of 4? Would that be because other thread writes updates the value to 0 from 4? This example is taken from jls https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.5

 class FinalFieldExample { 
        final int x;
        int y; 
        static FinalFieldExample f;

        public FinalFieldExample() {
            x = 3; 
            y = 4; 
        } 

        static void writer() {
            f = new FinalFieldExample();
        } 

        static void reader() {
            if (f != null) {
                int i = f.x;  // guaranteed to see 3  
                int j = f.y;  // could see 0
            } 
        } 
    }

Solution

  • Could you explain how the value of f.y could be seen 0 instead of 4?

    In Java, one of the important optimizations performed by the compiler/JVM is the reordering of instructions. As long as it doesn't violate the language specifications, the compiler is free to reorder all instructions for efficiency reasons. During object construction, it is possible for an object to be instantiated, the constructor to finish, and its reference published before all of the fields in the object have been properly initialized.

    However, Java language says that if a field is marked as final then it must be properly initialized by the time the constructor finishes. To quote from the section of the Java language specs you reference. Emphasis is mine.

    An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object after that object has been completely initialized is guaranteed to see the correctly initialized values for that object's final fields.

    So by the time the FinalFieldExample is constructed and assigned to f, the x field must be properly initialized to 3 however the y field may or may not have been properly initialized. So if thread1 makes the call to writer() and then thread2 makes the call to reader() and sees f as not null, y could be 0 (not yet initialized) or 4 (initialized).