面试题答案
一键面试单例模式的实现方式
-
饿汉式
public class Singleton { private static final Singleton INSTANCE = new Singleton(); private Singleton() {} public static Singleton getInstance() { return INSTANCE; } }
在类加载时就创建实例,保证了全局只有一个实例,并且这种方式是线程安全的,因为类加载机制由 JVM 保证线程安全。
-
懒汉式(线程不安全)
public class Singleton { private static Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
这种方式在第一次调用
getInstance
方法时才创建实例,实现了延迟加载,但在多线程环境下不安全,可能会创建多个实例。 -
懒汉式(线程安全,同步方法)
public class Singleton { private static Singleton instance; private Singleton() {} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
通过在
getInstance
方法上添加synchronized
关键字,保证了多线程环境下只有一个实例被创建,但每次调用getInstance
方法都需要进行同步操作,性能较低。 -
双重检查锁(DCL)
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
关键字防止指令重排,确保instance
初始化完成后才被其他线程访问。 -
静态内部类
public class Singleton { private Singleton() {} private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; } }
利用静态内部类的特性,在外部类加载时内部类不会被加载,只有在调用
getInstance
方法时才会加载并创建实例,实现了延迟加载且线程安全。 -
枚举
public enum Singleton { INSTANCE; // 可以在这里添加其他方法和属性 }
这是实现单例模式最简洁的方式,由 JVM 保证实例的唯一性和线程安全性,并且防止反序列化创建新的实例。
单例模式对内存优化的作用
- 减少对象创建次数:单例模式确保在整个应用程序生命周期中,某个类只有一个实例。如果不使用单例模式,每次需要使用该类的实例时都可能创建一个新的对象,这会导致大量的对象创建和销毁操作。例如,在一个应用中如果频繁创建数据库连接对象,会消耗大量内存。而使用单例模式,数据库连接对象只会被创建一次,后续所有对数据库连接的请求都复用这个唯一的实例,大大减少了对象创建次数,从而降低内存开销。
- 内存共享:单例对象在整个应用程序中是共享的,不同的模块或组件都可以使用同一个实例。这意味着对于一些资源消耗较大且不需要每个模块都单独拥有的对象(如配置文件读取器、日志记录器等),使用单例模式可以让它们在内存中只有一份,避免了重复创建相同功能对象带来的内存浪费,提高了内存的使用效率。