创建对已保存为成员字段的静态volatile变量的本地引用的目的或价值是什么。此处的代码来自java.util.Scanner JDK 6b14 here。
class Scanner {
private static volatile Pattern linePattern;
...
private static Pattern linePattern() {
Pattern lp = linePattern;
if (lp == null)
linePattern = lp = Pattern.compile("...");
return lp;
}
...
}
The Java Tutorials:“对于声明为volatile的所有变量(包括长变量和双变量),读取和写入都是原子的...对volatile变量的任何写入都会建立与之后读取同一变量的先发生关系。 “
这意味着读取Pattern对象的引用不会中途失败,因为它已经更改。 volatile关键字应该保护这些类型的访问,所以我不会复制局部变量来确保返回有效值。
此外,可以在成员字段上完成延迟初始化,而无需中间局部变量:
if (linePattern == null) linePattern = Pattern.compile("...");
看起来是here和here的字节码优化。使用局部变量产生较小的字节码(较少的指令)以及较少的实际值访问(这是一个昂贵的易失性读取)。然而,他们没有使用最终的变量优化,所以我对得出这个结论持怀疑态度。
答案 0 :(得分:2)
Lazy initialization,即推迟工作,直到确实有必要为止。
答案 1 :(得分:1)
它保证返回的值不为NULL - 即使在检查和返回之间将静态变量设置为NULL。
同时,如果需要,它是一个不同步的延迟初始化,重新初始化;)。
答案 2 :(得分:1)
volatile
变量非常昂贵。使用可以通过将其分配给堆栈变量并使用访问它来消除此开销
答案 3 :(得分:0)
对于volatile
字段,linePattern
可能会在不同的行之间发生变化。将引用复制到局部变量可确保您不会出现不一致的状态。例如,如果你写了
if (linePattern == null)
linePattern = Pattern.compile("...");
然后linePattern
可能在Pattern.compile
执行时已停止为空。