单例模式是一种设计模式,确保一个类只有一个实例,并提供一个全局访问点。以下是几种常见的单例模式实现方法及其优缺点:
1. 饿汉式单例(Eager Initialization)
实现
public class EagerSingleton {
private static final EagerSingleton INSTANCE = new EagerSingleton();
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return INSTANCE;
}
}
优点
- 简单,易于实现。
- 线程安全,因为实例在类加载时创建。
缺点
- 类加载时就创建实例,即使不使用也会创建,可能浪费资源。
2. 懒汉式单例(Lazy Initialization)
实现
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
优点
- 实例在第一次使用时才创建,节省资源。
缺点
- 不是线程安全的。如果多个线程同时调用
getInstance()
方法,可能会创建多个实例。
3. 线程安全的懒汉式单例(Thread-Safe Lazy Initialization)
实现
public class ThreadSafeLazySingleton {
private static ThreadSafeLazySingleton instance;
private ThreadSafeLazySingleton() {}
public static synchronized ThreadSafeLazySingleton getInstance() {
if (instance == null) {
instance = new ThreadSafeLazySingleton();
}
return instance;
}
}
优点
- 线程安全。
缺点
- 使用
synchronized
会导致性能开销,因为每次调用getInstance()
都会同步。
4. 双重检查锁定(Double-Checked Locking)
实现
public class DoubleCheckedLockingSingleton {
private static volatile DoubleCheckedLockingSingleton instance;
private DoubleCheckedLockingSingleton() {}
public static DoubleCheckedLockingSingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckedLockingSingleton.class) {
if (instance == null) {
instance = new DoubleCheckedLockingSingleton();
}
}
}
return instance;
}
}
优点
- 线程安全。
- 性能较好,减少了使用
synchronized
的开销。
缺点
- 代码相对复杂。
5. 静态内部类(Initialization-on-demand holder idiom)
实现
public class HolderSingleton {
private HolderSingleton() {}
private static class Holder {
private static final HolderSingleton INSTANCE = new HolderSingleton();
}
public static HolderSingleton getInstance() {
return Holder.INSTANCE;
}
}
优点
- 线程安全。
- 懒加载,实例在第一次使用时才创建。
- 不使用
synchronized
,性能好。
缺点
- 无明显缺点,是推荐的单例实现方式。
6. 枚举单例(Enum Singleton)
实现
public enum EnumSingleton {
INSTANCE;
public void doSomething() {
// 功能实现
}
}
优点
- 线程安全。
- 简单,自动支持序列化机制,防止反序列化重新创建新的对象。
- 防止反射攻击。
缺点
- 某些情况下可能不适合,比如需要继承其他类。
选择单例模式的注意事项
- 线程安全:在多线程环境中,确保单例的线程安全是关键。
- 懒加载:如果单例类资源消耗大,可以使用懒加载策略,只有在需要时才创建实例。
- 性能:在性能要求较高的场景下,选择性能较好的实现方式,比如双重检查锁定或静态内部类。
- 序列化:如果单例类需要支持序列化,确保在反序列化时不会创建新的实例。
总结
- 饿汉式单例:简单,线程安全,但可能浪费资源。
- 懒汉式单例:节省资源,但不是线程安全的。
- 线程安全的懒汉式单例:线程安全,但性能较差。
- 双重检查锁定:线程安全,性能较好,但代码复杂。
- 静态内部类:线程安全,性能好,推荐使用。
- 枚举单例:线程安全,简单,防止反射攻击,推荐使用。