单例模式(Singleton Pattern)是一种创建型设计模式,它保证一个类只有一个实例,并提供一个全局访问点。
单例模式的两种常见实现方式:懒汉式和饿汉式
- 饿汉式单例(Eager Initialization Singleton)
饿汉式单例在类加载时就创建实例,保证了线程安全,但可能导致不必要的资源浪费(如果实例迟迟未使用)。
代码实现:
public class HungrySingleton {
// 类加载时就初始化实例
private static final HungrySingleton instance = new HungrySingleton();
// 私有构造函数,防止外部创建实例
private HungrySingleton() {}
// 获取唯一实例的方法
public static HungrySingleton getInstance() {
return instance;
}
}
优点:实现简单,类加载时就完成实例化,避免了多线程同步问题。
缺点:即使实例未被使用,也会被提前创建,可能浪费资源。
- 懒汉式单例(Lazy Initialization Singleton)
懒汉式单例在需要时才创建实例,避免了饿汉式的资源浪费问题。但需要处理多线程并发的安全问题。
代码实现(非线程安全):
public class LazySingleton {
// 静态实例变量,开始时为 null
private static LazySingleton instance;
// 私有构造函数
private LazySingleton() {}
// 获取实例的方法
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
缺点:在多线程环境下可能出现多个实例(线程不安全)。
改进后的懒汉式单例(线程安全,双重检查锁定):
public class LazySingleton {
// 使用 volatile 修饰,防止指令重排
private static volatile LazySingleton instance;
private LazySingleton() {}
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
if (instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
}
优点:只有在需要时才创建实例,节约资源。通过双重检查锁定(Double-Checked Locking)机制确保线程安全,且避免每次都加锁,提高了性能。
缺点:相较饿汉式实现更为复杂。
懒汉式与饿汉式的区别:
-
实例化时间:
饿汉式在类加载时就创建实例。
懒汉式在第一次调用 getInstance() 方法时才创建实例。 -
线程安全:
饿汉式天然是线程安全的。
懒汉式需要通过同步机制(如 synchronized 或双重检查锁定)来保证线程安全。 -
资源利用:
饿汉式可能会造成资源浪费(如果实例一直未被使用)。
懒汉式更加节约资源,只有在需要时才实例化。
- 总结
如果确定实例在程序中始终会被使用,可以选择饿汉式简单实现;如果实例使用不确定且需要节省资源,可以选择懒汉式并加以线程安全控制。