I think I've read that the final keyword on a field guarantees that if thread 1 instantiates the object containing the field, then thread 2 will always see the initialized value of that field if thread 2 has a reference to the object (provided it was properly constructed). It also says in the JLS that
[Thread 2] will also see versions of any object or array referenced by those final fields that are at least as up-to-date as the final fields are. (section 17.5 of JLS)
That implies that if I have class A
class A { private final B b = new B(); private int aNotFinal = 2; ...
and class B
class B { private final int bFinal = 1; private int bNotFinal = 2; ...
then aNotFinal is not guaranteed to be initialized by the time thread 2 gets a reference to class A, but field bNotFinal is, because B is an object referenced by a final field, as specified in the JLS.
Do I have this right?
Edit:
A scenario where this could happen would be if we have two threads concurrently executing getA() on the same instance of a class C
class C { private A a; public A getA(){ if (a == null){ // Thread 1 comes in here because a is null. Thread B doesn't come in // here because by the time it gets here, object c // has a reference to a. a = new A(); } return a; // Thread 2 returns an instance of a that is not fully // initialized because (if I understand this right) JLS // does not guarantee that non-final fields are fully // initialized before references get assigned } }
The final keyword is a non-access modifier used for classes, attributes and methods, which makes them non-changeable (impossible to inherit or override). The final keyword is useful when you want a variable to always store the same value, like PI (3.14159...). The final keyword is called a "modifier".
If a variable is declared with the final keyword, its value cannot be changed once initialized.
Final Variables are also thread-safe in java because once assigned some reference of an object It cannot point to reference of another object.
In Java, the final keyword is used to denote constants. It can be used with variables, methods, and classes. Once any entity (variable, method or class) is declared final , it can be assigned only once.
What you are saying is true.
Marking a field as final forces the compiler to complete initialization of the field before the constructor completes. There is no such guarantee however for non-final fields. This might seem weird, however there are many things done by the compiler and JVM for optimization purposes such as reordering instructions, that cause such stuff to occur.
The final keyword has many more benefits. From the Java Concurecncy in Practice:
Final fields can't be modified (although the objects they refer to can be modified if they are mutable), but they also have special semantics under the Java Memory Model. It is the use of final fields that makes possible the guarantee of initialization safety (see Section 3.5.2) that lets immutable objects be freely accessed and shared without synchronization.
The Books says then:
To publish an object safely, both the reference to the object and the object's state must be made visible to other threads at the same time. A properly constructed object can be safely published by:
- Initializing an object reference from a static initializer;
- Storing a reference to it into a volatile field or AtomicReference;
- Storing a reference to it into a final field of a properly constructed object; or
- Storing a reference to it into a field that is properly guarded by a lock.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With