I have a hunch that using the holder idiom without declaring the holder field as final is not thread safe (due to the way immutability works in Java). Can somebody confirm this (hopefully with some sources)?
public class Something {
private long answer = 1;
private Something() {
answer += 10;
answer += 10;
}
public int getAnswer() {
return answer;
}
private static class LazyHolder {
// notice no final
private static Something INSTANCE = new Something();
}
public static Something getInstance() {
return LazyHolder.INSTANCE;
}
}
EDIT: I definitely want sourced statements, not just assertions like "it works" -- please explain/prove it's safe
EDIT2: A little modification to make my point more clear - can I be sure that the getAnswer() method will return 21 regardless of calling thread?
The class initialization procedure guarantees that if a static field's value is set using a static initializer (i.e. static variable = someValue;
) that value is visible to all threads:
10 - If the execution of the initializers completes normally, then acquire LC, label the Class object for C as fully initialized, notify all waiting threads, release LC, and complete this procedure normally.
Regarding your edit, let's imagine a situation with two threads T1 and T2, executing in that order from a wall clock's perspective:
- T1:
Something s = Something.getInstance();
- T2:
Something s = Something.getInstance(); i = s.getAnswer();
Then you have:
- T1 acquire LC, T1 run
Something INSTANCE = new Something();
, which initialises answer
, T1 release LC
- T2 tries to acquire LC, but already locked by T1 => waits. When T1 releases LC, T2 acquire LC, reads
INSTANCE
then reads answer
.
So you can see that you have a proper happens-before relationship between the write and the read to answer
, thanks to the LC
lock.
It is thread-safe for sure, but is mutable. So anyone who gets it may assign it to something else. And that is first thing to worry about (even before considering thread-safety).