下面是 Effective Java 第二版的一个片段。作者声称以下代码比不使用 result
变量的代码快 25%。
根据这本书“这个变量的作用是确保该字段在已经初始化的常见情况下只被读取一次。” .
我无法理解为什么与不使用局部变量 result 相比,初始化值后这段代码会更快。在任何一种情况下,无论您是否使用局部变量 result,您在初始化后都将只有一次 volatile 读取。
// 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;
}
最佳答案
一旦 field
被初始化,代码是:
if (field == null) {...}
return field;
或:
result = field;
if (result == null) {...}
return result;
在第一种情况下,您读取了 volatile 变量两次,而在第二种情况下,您只读取了一次。虽然 volatile 读取非常快,但它们可能比从局部变量读取慢一点(我不知道是不是 25%)。
注意事项:
- volatile 读取与最近的处理器(至少 x86)/JVM 上的正常读取一样便宜,即没有区别。
- 然而,编译器可以更好地优化没有 volatile 的代码,因此您可以从更好的编译代码中获得效率。
- 无论如何,25% 的几纳秒仍然不算多。
- 这是一个标准习语,您可以在 java.util.concurrent 包的许多类中找到它 - 例如参见 this method in ThreadPoolExecutor (有很多)
关于java - 为什么在 Joshua Bloch Effective Java Example 中双重检查锁定快 25%,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17164454/