懒汉式单例模式适用场景及类加载相关技术疑问
关于单例模式的两个问题解答
1. 懒汉式单例模式的适用场景
饿汉式与懒汉式的核心差异在于实例初始化时机:饿汉式在类加载阶段就完成实例创建,懒汉式则延迟到首次调用getInstance()方法时才初始化实例。你的示例中因为直接调用了两个单例的getInstance(),所以看起来无差异,但以下场景中懒汉式的优势会凸显:
- 单例初始化成本极高:如果单例对象需要加载大配置文件、初始化复杂缓存或建立数据库连接池等资源,而该类可能被加载但永远不会被实际使用,懒汉式能避免不必要的资源占用。比如某个仅在特定业务分支才会触发的工具类单例,饿汉式会在程序启动时就消耗资源,懒汉式则只在真正需要时初始化。
- 依赖运行时动态参数:饿汉式的实例初始化在类加载阶段,无法获取环境变量、用户输入等运行时参数。懒汉式可以在
getInstance()方法中读取动态数据,完成实例的灵活初始化。 - 优化程序启动速度:若应用中存在多个初始化成本高的饿汉式单例,会拖慢启动速度。懒汉式将初始化工作延迟到实际使用时,能有效缩短启动时间。
2. JVM加载单例类但未使用实例的场景
JVM的类加载触发于首次主动使用,但主动使用的场景不止调用getInstance(),以下情况会导致单例类被加载但实例未被使用(或未被创建):
针对懒汉式单例
- 调用单例类的非
getInstance()静态方法:比如Singleton1有public static void printInfo()方法,其他类调用该方法时,JVM会加载Singleton1类,但instance不会被初始化。 - 访问单例类的非
instance静态字段:比如Singleton1定义了public static final String VERSION = "1.0",其他类读取该字段时,类会被加载,但instance不会创建。
针对饿汉式单例
- 类被加载后实例已创建,但程序从未调用
getInstance()获取实例:比如其他类通过反射访问单例的私有构造,或调用其其他静态方法导致类加载,实例被创建但从未被实际使用。 - 单例类作为其他类的静态字段类型:比如
public class SomeClass { private static Singleton singleton; },当SomeClass被加载时,JVM解析Singleton类型会触发类加载,实例被创建,但SomeClass的singleton字段从未被赋值或使用。
示例代码的差异验证
你的示例中因直接调用getInstance(),所以两种单例的实例都会立即创建。修改代码后即可看到差异:
class Main{ public static void main(String[] args) { // 调用Singleton1的静态方法,不获取实例 Singleton1.printHello(); } } class Singleton1{ private Singleton1(){ System.out.println("Singleton1实例被创建"); } private volatile static Singleton1 instance=null; public static Singleton1 getInstance(){ if(instance==null){ synchronized (Singleton1.class){ if(instance==null){ instance=new Singleton1(); } } } return instance; } public static void printHello(){ System.out.println("Hello"); } }
运行该代码只会输出Hello,不会触发Singleton1实例的创建;如果是饿汉式单例,只要类被加载(调用静态方法),实例就会被创建,会输出实例初始化的日志。
内容的提问来源于stack exchange,提问作者jcli
相关产品推荐
相关产品推荐

