为什么在双重检查锁定中使用volatile?
为什么在双重检查锁定中使用volatile?
来自《Head First设计模式》的书,双重检查锁定的单例模式被实现如下:
public class Singleton { private volatile static Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
我不明白为什么要使用volatile
。使用volatile
不是会削弱双重检查锁定的目的,即提高性能吗?
admin 更改状态以发布 2023年5月22日
如@irreputable所引述的,volatile不昂贵。即使它很昂贵,一致性应该优先于性能。
还有一种干净优雅的方法可以实现懒惰单例。
public final class Singleton { private Singleton() {} public static Singleton getInstance() { return LazyHolder.INSTANCE; } private static class LazyHolder { private static final Singleton INSTANCE = new Singleton(); } }
来源文章:Initialization-on-demand_holder_idiom,来自维基百科
在软件工程中,初始化-on-demand持有者(设计模式)习惯用法是一种懒加载的单例。在Java的所有版本中,这种习惯用法可以实现安全、高度并发的懒初始化和良好的性能。
由于该类不具有任何要初始化的静态变量,因此初始化可以轻松完成。
其内部的静态类定义LazyHolder
直到JVM确定必须执行LazyHolder
时才会初始化。
只有在类Singleton上调用静态方法getInstance
并且第一次发生这种情况时,JVM才会加载和初始化静态类LazyHolder
。
这种解决方案是线程安全的,无需特殊的语言结构(即volatile
或synchronized
)。