如何在 Java 中实现单例模式
在 Java 中实现单例模式有几种常见的方式,下面是几种典型实现:
1. 饿汉式(Eager Initialization)
这种方式的特点是,单例实例在类加载时就会被创建。
public class Singleton {
// 1. 创建静态实例
private static final Singleton INSTANCE = new Singleton();
// 2. 私有构造方法,防止外部实例化
private Singleton() {}
// 3. 提供公共的访问方法
public static Singleton getInstance() {
return INSTANCE;
}
}
特点:
- 简单易懂,线程安全。
- 无论是否使用该单例,类加载时都会创建实例。
2. 懒汉式(Lazy Initialization)
单例实例在首次使用时才创建。需要保证线程安全。
public class Singleton {
// 1. 声明单例实例,延迟初始化
private static Singleton instance;
// 2. 私有构造方法,防止外部实例化
private Singleton() {}
// 3. 提供公共的访问方法,使用同步控制线程安全
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
特点:
- 延迟加载,只有在需要时才会创建实例。
- 线程安全,但每次访问时都要进行同步,性能相对较低。
3. 双重检查锁(Double-Checked Locking)
为了优化性能,可以使用双重检查锁定(DCL)模式,只有在实例为空时才会加锁,避免了每次调用时都加锁的性能问题。
public class Singleton {
// 1. 声明单例实例,使用 volatile 保证内存可见性
private static volatile Singleton instance;
// 2. 私有构造方法,防止外部实例化
private Singleton() {}
// 3. 提供公共的访问方法,进行双重检查锁定
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
特点:
- 线程安全且性能较好。
- 需要使用
volatile
关键字,保证对instance
的写入是有序的。
4. 静态内部类(Bill Pugh Singleton)
这种方法通过静态内部类的加载来实现延迟加载,并且线程安全。它是实现单例模式的最佳方式之一。
public class Singleton {
// 1. 私有构造方法,防止外部实例化
private Singleton() {}
// 2. 静态内部类,只有在调用时才会加载
private static class SingletonHelper {
// 3. 静态实例,实例在类加载时创建
private static final Singleton INSTANCE = new Singleton();
}
// 4. 提供公共的访问方法
public static Singleton getInstance() {
return SingletonHelper.INSTANCE;
}
}
特点:
- 延迟加载,且线程安全。
- 通过静态内部类加载机制,只有在第一次调用
getInstance()
时,SingletonHelper
类才会被加载,保证了懒加载的效果。
5. 枚举式(Enum Singleton)
Java 中枚举类型的单例实现是最简洁且安全的,Java 会确保枚举实例的唯一性和线程安全。
public enum Singleton {
INSTANCE;
// 1. 可以添加方法和字段
public void doSomething() {
// 业务逻辑
}
}
特点:
- 最简洁的实现方式,确保了单例的线程安全。
- 不允许使用反射来破坏单例,推荐使用这种方式。
总结:
- 如果不需要延迟初始化,可以使用饿汉式单例。
- 如果需要延迟初始化且关注性能,可以使用双重检查锁。
- 如果追求代码简洁且安全,可以使用枚举式单例。
#全栈开发
分享于 2025-01-09