问题
Hi below is the snippet from Effective Java 2nd Edition. Here the author claims the following piece of code is 25% faster more than in which u do not use result variable. According to the book "What this variable does is to ensure that field is read only once in the common case where it’s already initialized." . I am not able to understand why this code would be fast after the value is initialized as compare to of if we do not use the Local variable result. In either case you will have only one volatile read after initialization whether you use the local variable result or not.
// Double-check idiom for lazy initialization of instance fields
private volatile FieldType field;
FieldType getField() {
FieldType result = field;
if (result == null) { // First check (no locking)
synchronized(this) {
result = field;
if (result == null) // Second check (with locking)
field = result = computeFieldValue();
}
}
return result;
}
回答1:
Once field has been initialised, the code is either:
if (field == null) {...}
return field;
or:
result = field;
if (result == null) {...}
return result;
In the first case you read the volatile variable twice whereas in the second you only read it once. Although volatile reads are very fast, they can be a little slower than reading from a local variable (I don't know if it is 25%).
Notes:
- volatile reads are as cheap as normal reads on recent processors (at least x86)/JVMs, i.e. there is no difference.
- however the compiler can better optimise a code without volatile so you could get efficiency from better compiled code.
- 25% of a few nanoseconds is still not much anyway.
- it is a standard idiom that you can find in many classes of the java.util.concurrent package - see for example this method in ThreadPoolExecutor (there are many of them)
回答2:
Without using a local variable, in most invocations we have effectively
if(field!=null) // true
return field;
so there are two volatile reads, which is slower than one volatile read.
Actually JVM can merge the two volatile reads into one volatile read and still conform to JMM. But we expect JVM to perform a good faith volatile read every time it's told to, not to be a smartass and try to optimize away any volatile read. Consider this code
volatile boolean ready;
do{}while(!ready); // busy wait
we expect JVM to really load the variable repeatedly.
来源:https://stackoverflow.com/questions/17164454/why-double-checked-locking-is-25-faster-in-joshua-bloch-effective-java-example