Most probably you've got your answer by now, but just to make sure I wanted to add my explanation also.
In order for an object (for your case) to be thread-safe, it must:
- Be immutable
- Be safely published
Immutable - you made it so. There is no way to modify bar once it has been set. Pretty obvious here.
Safely published. As per the example, the code is not safely published. Because bar is not final the compiler is free to reorder it as it finds appropriate. The compiler could publish(write to main memory) the reference to Foo instance, before the write to bar. That would mean that bar is null. So, first the reference to Foo is written to main memory, then the write to bar happens. In between these two events another thread can see the stale bar as being null.
If you add final to it, the JMM will guarantee that:
the values of final fields are guaranteed to be visible to other threads accessing the constructed object.
Or, final field prevents reordering. Thus making that variable final will ensure thread safety.