Java 静态在JMM上下文中提供额外的保证吗?
我正在读关于java singleton的书,我遇到了一些奇怪的事情 我将举一个例子(你可以很容易找到更多) 作者提供了以下单例:Java 静态在JMM上下文中提供额外的保证吗?,java,multithreading,concurrency,visibility,java-memory-model,Java,Multithreading,Concurrency,Visibility,Java Memory Model,我正在读关于java singleton的书,我遇到了一些奇怪的事情 我将举一个例子(你可以很容易找到更多) 作者提供了以下单例: public class ASingleton { private static ASingleton instance = new ASingleton(); private ASingleton() { } public static ASingleton getInstance() {
public class ASingleton {
private static ASingleton instance = new ASingleton();
private ASingleton() {
}
public static ASingleton getInstance() {
return instance;
}
}
和评论:
优点:-无同步的线程安全性
-易于实现 缺点:
-早期创建可能不在应用程序中使用的资源。
-客户端应用程序无法传递任何参数,因此我们无法重用它。
例如,具有用于数据库连接的通用单例类
其中客户端应用程序提供数据库服务器属性 我想澄清一下没有同步的线程安全问题 我读过实践书中的并发性,但不记得与此相关的任何内容 我遗漏了什么或者这个澄清不相关 此外,我想告诉您,您可以遇到相同的单例,但字段标记为
static final
,而不仅仅是static
P.S. 我知道我可以阅读,这本书包含了答案,但我是一个普通人,我无法理解这个来源。根据这是一个有效的模式: 声明为静态并在声明时或从静态初始值设定项初始化的变量保证在对其他线程可见之前完全构造。但是,此解决方案放弃了延迟初始化的好处 要点是:加载类是一个定义良好的操作。执行静态初始化代码属于同一类 理解这一点很重要:当您选择
静态字段时,JMM知识只是“必需的”:
静态帮助器字段的初始化延迟到调用getInstance()方法。在通过类加载器加载和初始化Holder实例的操作以及Java内存模型(JMM)提供的保证组合创建关系之前,需要进行必要的操作。对于惰性地初始化静态字段,这个习惯用法比双重检查锁定习惯用法更好[Bloch 2008]。但是,这个习惯用法不能用于惰性地初始化实例字段[Bloch 2001]
Final
ly:Final
关键字应该不会影响这一点。使用final
更多的是表达你想要声明一个好的、最终的东西的意图,而不是一个以后可能会更新的东西 根据这是一个有效的模式:
声明为静态并在声明时或从静态初始值设定项初始化的变量保证在对其他线程可见之前完全构造。但是,此解决方案放弃了延迟初始化的好处
要点是:加载类是一个定义良好的操作。执行静态初始化代码属于同一类
理解这一点很重要:当您选择静态字段时,JMM知识只是“必需的”:
静态帮助器字段的初始化延迟到调用getInstance()方法。在通过类加载器加载和初始化Holder实例的操作以及Java内存模型(JMM)提供的保证组合创建关系之前,需要进行必要的操作。对于惰性地初始化静态字段,这个习惯用法比双重检查锁定习惯用法更好[Bloch 2008]。但是,这个习惯用法不能用于惰性地初始化实例字段[Bloch 2001]
Final
ly:Final
关键字应该不会影响这一点。使用final
更多的是表达你想要声明一个好的、最终的东西的意图,而不是一个以后可能会更新的东西 这个成语对于JMM来说是正确的
类的静态初始化和任何静态变量的使用之间存在一种先发生后发生的关系。这是在中描述的初始化过程中发生锁定的结果
根据我的阅读,实例
不需要在这里声明为最终
,以获得所需的数据。不过,出于其他原因,我们还是建议使用这个成语
类的静态初始化和任何静态变量的使用之间存在一种先发生后发生的关系。这是在中描述的初始化过程中发生锁定的结果
根据我的阅读,实例
不需要在这里声明为最终
,以获得所需的数据。但是,出于其他原因,这是可取的。您没有可见性的保证(这将赋予线程安全性),因为该字段不是最终的
@Andy,是的,我已经更正了一点,因为文本与代码无关。我想作者描述了我提供的变体,它必须是静态final
,才能获得所描述的属性。注意!当作者说“线程安全”时,这并不意味着它使整个单例线程安全。这只意味着getInstance()
方法是线程安全的。调用getInstance()
的线程永远不会看到处于部分初始化或未初始化状态的singleton对象。@为什么?getInstance未同步您没有可见性保证(这将赋予线程安全性),因为该字段不是final
@Andy,是的,我已经更正了一点,因为文本与代码无关。我想作者描述了我提供的变体,它必须是静态final
,才能获得属性