为什么同时使用局部变量和volatile来同时进行DCL(如Sonar工具所建议)?

时间:2019-05-28 19:01:06

标签: java multithreading sonarqube synchronized double-checked-locking

有相关的questions,但是作为重点,它们更多地是在volatile上,而不是在局部变量的使用上,因此,我要发布一个新问题,请参阅下面的问题。

声纳来源rule的代码正确无误,并解决了DCL的问题

class ResourceFactory {
  private volatile Resource resource;

  public Resource getResource() {
    Resource localResource = resource;
    if (localResource == null) {
      synchronized (this) {
        localResource = resource;
        if (localResource == null) {
          resource = localResource = new Resource();
        }
      }
    }
    return localResource;
  }

  static class Resource {
  }
}

我了解我们有其他选择(比复杂的DCL更好),例如

  1. 枚举或
  2. 静态内部类持有人或
  3. 在声明本身期间初始化的静态最终引用。
  4. 将整个方法声明为已同步。

我希望了解使用volatile和局部变量来解决DCL问题。

我也理解volatile(对于Java 1.5和更高版本)保证了“发生之前”功能,该功能可以防止返回不完整的对象以供读取。

问题1 我想理解的是,如果已经使用了局部变量,那么对volatile的需求是什么。下面的代码具有非易失性变量resource,但是在getResource()内使用局部变量读取resource。代码中还有问题吗? (请在下面的代码中查看注释)

class ResourceFactory {
  private Resource resource; // non volatile
  public Resource getResource() {
    Resource localResource = resource; // only 1 read without lock
    if (localResource == null) {
      synchronized (this) {
        localResource = resource; // read inside the synchronized block
        if (localResource == null) {
           localResource = new Resource(); // constructor is initialized. 
           resource = localResource; // ****code reaches here only when constructor has been complete. Here is there a chance of resource being referring to incomplete object ?**** 
        }
      }
    }
    return localResource;
  }

  static class Resource {
  }
}

我看到的唯一优势是volatile,它是假定对象已创建,然后第一次读取本身就可以保证内存读取,而不是从线程缓存读取,从而避免了不必要的锁获取。

问题2 如果使用简单的volatile而不是使用局部变量,那么代码没有问题吗?

1 个答案:

答案 0 :(得分:2)

有效的Java 直接解决了问题2;虽然它也可能在其他版本中提到,但我面前的是第三版,第83条,p335:

  

代码可能看起来有些混乱。特别是,对局部变量(result)的需求可能不清楚。该变量的作用是确保field在已经初始化的常见情况下仅被读取一次。尽管不是绝对必要的,但是这可以提高性能,并且通过应用于低级并发编程的标准可以更加优雅。在我的机器上,上述方法的速度是不带局部变量的明显方法的1.4倍。

(请注意,在早期印刷中,第三版Ed的代码示例中有一个严重错误,用于双重检查锁定(立即在此引号之前!请查看勘误以获取更正的代码。)