1

I recently got confused when i referred to JMM for guarantees associated with "final". Here is an excerpt and example from JMM

Figure 4 gives an example that demonstrates how final fields compare to normal fields. The class FinalFieldExample has a final int field x and a non-final int field y. One thread might execute the method writer(), and another might execute the method reader(). Because writer() writes f after the object’s constructor finishes, the reader() will be guaranteed to see the properly initialized value for f.x: it will read the value 3. However, f.y is not final; the reader() method is therefore not guaranteed to see the value 4 for it

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
      }
    }
}

My confusion is that is an object 'Obj' has final and non-final fields is fully initialized and is being referenced by a Thread 'T', T will only see correct values for final fields ? What about non-final fields that are not mutated after construction. I understand that if they are mutated after construction thread 'T' might not see new value ( unless the field is a volatile ). But i am what if the field is non-final and non-volatile and is not mutated after construction ?

How does JVM implements guarantees associated with 'final' ? E.g for volatile there are memory barriers.

Gray
  • 115,027
  • 24
  • 293
  • 354
snegi
  • 636
  • 1
  • 6
  • 22
  • Answer here: http://stackoverflow.com/questions/10301061/is-this-a-safe-publication-of-object/10301179#10301179 – Gray Nov 13 '13 at 23:40
  • there's a bug in this code - after the `if(f!=null)` check, `f` could appear to be null again. the code should use a local variable to cache `f` – ZhongYu Nov 14 '13 at 02:35
  • http://stackoverflow.com/a/15342485/2031799 - this is how final fields are implemented. In theory this example might break, but not in practice. – Mikhail Nov 15 '13 at 07:38

3 Answers3

7

This is addressed in this answer:

Is this a safe publication of object?

To quote:

The issue revolves around optimizations and reordering of instructions. When you have two threads that are using a constructed object without synchronization, it may happen that the compiler decides to reorder instructions for efficiency sake and allocate the memory space for an object and store its reference in the item field before it finishes with the constructor and the field initialization. Or it can reorder the memory synchronization so that other threads perceive it that way.

If you mark a field as final it forces the compiler to complete initialization for that field before the constructor completes. Non-final fields have no such guarantees.

This is part of the Java language definition (17.4). Details about final fields are also in the JLS (17.5).

More specifically, the writer() method constructs an instance of FinalFieldExample and stores in in a static field for other threads to consume. Because of instruction reordering, the y field may not have been initialized yet. If the same thread calls the reader() it will see y as 4 but other threads could see it as 0 because f was set and consumed possibly before y gets initialized and published.

To make this code correct, you must make f be volatile as well.

Community
  • 1
  • 1
Gray
  • 115,027
  • 24
  • 293
  • 354
  • Gray. Thanks for reply. While compiler reordering instructions ( ByteCode instructions, not program instructions ) explains why f.y will not return 4. The JMM says : "Because writer() writes f after the object’s constructor finishes". So to me it seems that specification is ruling out such reordering. – snegi Nov 13 '13 at 23:59
  • Added more details @snegi. The constructor could finish, the `f` field set, other threads could read `f.y`, and _then_ it could be initialized. Or the initialization may not have been published. – Gray Nov 14 '13 at 00:05
  • But if contructor is finished f.y field is already assigned a value, right ? – snegi Nov 14 '13 at 00:10
  • 1
    No. That's the point of the instruction reordering @snegi. Non-final fields can be assigned _after_ the constructor finishes. – Gray Nov 14 '13 at 00:13
  • Thanks again Gray. I understand instruction reordering in other contexts, but wasnt aware of this non-final behavior. Any idea what is the reason behind this behavior ? I mean i am trying to think what optimization is achieved this way. – snegi Nov 14 '13 at 00:17
  • I just noticed that you mentioned that to make the code correct we need to make f volatile as well. While i do understand volatile read semantics. But in this case, are you saying that if 'f' is volatile then constructor would not finish until all non-final fields are also initialized ? – snegi Nov 14 '13 at 00:20
  • 3
    @snegi if `f` is volatile, the write to `y` cannot be reordered after the write to `f` – ZhongYu Nov 14 '13 at 02:39
  • zhong is right @snegi. The `volatile` imposes a happens-before relationship and ensures memory synchronization. The constructor must finish before `f` can be published. – Gray Nov 14 '13 at 13:29
  • Compiler reordering is one of the major optimizations available to the JVM. I'm not 100% sure why it was specifically chosen but optimization is definitely the reason @snegi. – Gray Nov 14 '13 at 13:35
  • Huh? I don't get your comment @RobinGreen. My answer explains and shows references to the JLS around `final` field handling. It is about instruction reordering. Specifically how do you think I'm contradicting the JMM because I'm not. – Gray Nov 21 '13 at 14:52
  • @Gray sorry, I misread your answer – Robin Green Nov 21 '13 at 20:40
  • I've edited my answer in case you want to withdraw your downvote @RobinGreen. – Gray Nov 22 '13 at 13:08
3

How does JVM implements guarantees associated with 'final' ? E.g for volatile there are memory barriers.

To honor the semantics of final fields, some reordering cannot be done, and some memory barriers may be needed (on some processors). see http://g.oswego.edu/dl/jmm/cookbook.html

This means final is not free lunch. Take that into consideration before we use final everywhere. (Just because it's in Joshua's book doesn't mean it is correct)

ZhongYu
  • 19,446
  • 5
  • 33
  • 61
1

My confusion is that is an object 'Obj' has final and non-final fields is fully initialized and is being referenced by a Thread 'T', T will only see correct values for final fields?

All threads are guaranteed to see correct values for final fields. This says nothing about non-final fields.

What about non-final fields that are not mutated after construction.

The final modifier applies only to a specific field. You may "get lucky" with other non-final fields, but the guarantee applies only to the fields marked as final.

The fact that a non-final field is set in the constructor and not modified later is irrelevant.

user2864740
  • 60,010
  • 15
  • 145
  • 220
  • 1
    In der practice it seems to be sufficient to have at least one final field in the class to make all the other fields visible. StoreStore barrier synchronized everything and JIT compiler does not reorder code over the constructor borders. It is definitely NOT a good idea to rely on this behavior. – 30thh Dec 17 '16 at 14:28