静态是否在JMM上下文中提供了额外的保证?

时间:2017-08-30 11:28:53

标签: java multithreading concurrency visibility java-memory-model

我正在阅读有关java singleton的内容,而且我遇到了一些奇怪的事情。

我将以following artice为例(您可以轻松找到更多)

作者提供以下单身人士:

public class ASingleton {

    private static ASingleton instance = new ASingleton();

    private ASingleton() {
    }

    public static ASingleton getInstance() {            
        return instance;
    }

}

和评论:

  

优点:
    - 没有同步的线程安全
    - 易于实施

     

缺点:
    - 尽早创建可能未在应用程序中使用的资源     - 客户端应用程序无法传递任何参数,因此我们无法重复使用它        例如,具有用于数据库连接的通用单例类
     客户端应用程序提供数据库服务器属性的位置。

我希望澄清没有同步的线程安全点。

我已经阅读了练习册中的并发性,并且不记得与此相关的任何内容。

我错过了什么或者这个澄清是不相关的?

此外,我想告诉您,您可以遇到相同的单身,但字段标记为static final,而不仅仅是static
P.S。

我知道我可以阅读JMM,但这个包含答案,但我是平常的人,而且我不能承认这个来源。

2 个答案:

答案 0 :(得分:2)

这个成语对于JMM来说是合理的。

在类的静态初始化和使用任何静态变量之间存在之前的关系。这是JLS 12.4.2中描述的初始化过程期间发生锁定的结果。

根据我的阅读,instance不需要在此处声明为final,以便在之前获得所需的。不过,建议其他原因。

答案 1 :(得分:1)

根据securecoding.cert.org,这是一种有效的模式:

  

在声明或静态初始值设定项中声明为静态和初始化的变量保证在对其他线程可见之前完全构造。但是,此解决方案可以避免延迟初始化的好处。

重点是:加载类是一个定义良好的操作。并且执行静态初始化代码属于同一类别。

重要的是要理解:JMM知识只是"必需"当你选择static field + lazy init变种时:

  

在调用getInstance()方法之前,将推迟静态辅助对象字段的初始化。通过加载和初始化Holder实例的类加载器操作和Java内存模型(JMM)提供的保证的组合创建必要的发生之前的关系。对于懒惰地初始化静态场而言,这个成语是比双重检查锁定习惯更好的选择[Bloch 2008]。但是,这个习惯用法不能用于懒惰地初始化实例字段[Bloch 2001]。

Finalfinal关键字根本不会影响这一点。使用final更多的是关于表达您声明井,最终事物的意图 - 而不是稍后可能更新的事物。