From the java
docs of final field
semantics:
They are guaranteeing to see the final
field as set in constructor
, please find the code below:
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
}
}
}
Now here I am confused about volatile
vs final
.
To my understanding final
filed is used make sure you can not change the variable in application and volatile
guarantees to maintain the order and avoid happen before relationship.
So my question is how come they guarantee the visibility and ordering using final
variable instead of volatile
? Please help.
So my question is how come they guarantee the visibility and ordering using final variable
Because they defined it that way, and it's now the job of the VM to adhere to this definition.
Of course, the follow-up question is: Why did they define it that way?
It's because of a weird "feature" of the Java memory model. Consider this example
class Foo {
int x;
volatile int y;
Foo() {
x = 3;
y = 4;
}
static final Foo INSTANCE;
static {
INSTANCE= new Foo();
}
}
The static intitializer will be compiled into this (simplified pseudocode):
Foo tmp = allocate(Foo.class)
Foo.INSTANCE = tmp
tmp.x = 3
tmp.y = 4
As you can see, the instance is made public before the constructor is executed, volatile
doesn't change anything here.
This behavior is unexpected for most developer and can lead to very hard-to-debug bugs. Thus, to reduce the extend of this issue a bit, the specification was adjusted to require final fields to be initialized before the instance is made public.
Example from above, with x
declared final
.
Foo tmp = allocate(Foo.class)
tmp.x = 3
Foo.INSTANCE = tmp
tmp.y = 4