以下是Effective Java 2nd Edition的片段。在这里,作者声称下面的代码比你不使用结果变量快25%。 根据书中的“这个变量的作用是确保该字段在已经初始化的常见情况下只读取一次。” 。 我无法理解为什么这个代码在初始化之后会比较快,如果我们不使用Local变量结果。在任何一种情况下,无论是否使用局部变量结果,初始化后只有一个易失性读取。
// 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;
}
答案 0 :(得分:9)
初始化field
后,代码为:
if (field == null) {...}
return field;
或:
result = field;
if (result == null) {...}
return result;
在第一种情况下,您读取两次volatile变量,而在第二种情况下,您只读取一次。虽然易失性读取非常快,但它们比从局部变量读取要慢一些(我不知道它是否为25%)。
注意:
答案 1 :(得分:0)
在不使用局部变量的情况下,在大多数调用中我们都有效
if(field!=null) // true
return field;
因此有两个易失性读取,比一个易失性读取慢。
实际上,JVM可以将两个易失性读取合并为一个易失性读取,并且仍然符合JMM。但是我们希望JVM每次被告知时都要执行一个良好的易失性读取,而不是智能手机,并试图优化掉任何易失性读取。考虑一下这段代码
volatile boolean ready;
do{}while(!ready); // busy wait
我们希望JVM能够重复加载变量。