初始化静态变量时使用局部变量

时间:2018-11-20 23:52:53

标签: java variables static initialization

java.util.Scanner的源代码中,我发现了这些静态实用程序方法:

private static Pattern separatorPattern() {
    Pattern sp = separatorPattern;
    if (sp == null)
        separatorPattern = sp = Pattern.compile(LINE_SEPARATOR_PATTERN);
    return sp;
}

private static Pattern linePattern() {
    Pattern lp = linePattern;
    if (lp == null)
        linePattern = lp = Pattern.compile(LINE_PATTERN);
    return lp;
}

为什么要以如此复杂的方式进行操作,而不仅仅是说

private static Pattern linePattern() {
    if (linePattern == null)
        linePattern = Pattern.compile(LINE_PATTERN);
    return linePattern;
}

在这里使用局部变量(lp)有什么意义?这是某种优化技术吗?还是预防并发修改?但是linePattern不能再次设置为null,因为此方法是唯一对其进行修改的地方。

2 个答案:

答案 0 :(得分:3)

我相信这完全是与volatilelinePattern字段一起使用的separatorPattern关键字

private static volatile Pattern separatorPattern;
private static volatile Pattern linePattern;

由于specification

  

Java编程语言允许线程访问共享变量(第17.1节)。通常,为确保共享变量被一致且可靠地更新,线程应通过获取通常对这些共享变量强制互斥的锁来确保其专有使用此类变量。

     

Java编程语言提供了第二种机制,即volatile字段,它比出于某些目的的锁定更方便。

     

字段可以声明为volatile,在这种情况下,Java内存模型可确保所有线程看到的变量值都是一致的

here也可以阅读

  

声明一个易失的Java变量意味着:

     
      
  • 此变量的值永远不会在线程本地缓存:所有读写操作都将直接进入“主内存”;

  •   
  • 对变量的访问就像是将其封装在一个已同步的块中,且已同步。

  •   

这就是为什么他们首先尝试直接读取字段的值,然后用新值覆盖它的原因

答案 1 :(得分:2)

我认为他们希望避免两次从volatile字段中读取。

  • 一次检查是否为null
  • 一次return

在他们的版本中,只有

  • 将其读入局部变量
  • 确认本地变量不为空
  • 返回该局部变量

对于“快乐路径”的优化比仅发生一次的“初始设置路径”发生的频率高得多,如果该方法在完成初始化之前被并发调用,则优化最多可以进行几次。 / p>

  

或者是防止同时进行修改的预防措施?

没有这样的预防措施。如果您在完成设置静态volatile字段之前并发调用linePattern,该模式将被创建多次(但是没关系),将返回不同的实例,并且将随机选择其中的一个实例(也可以,因为它们是等效的。

任何防止这种情况的措施只会增加我们“幸福之路”的成本,因此只能在由于某种原因该实例确实确实是单身的情况下才可以这样做。