在Java中,单例类(Singleton Class) 是一种设计模式,用于确保一个类只有一个实例,并提供一个全局访问点来获取该实例。单例模式通常用于管理共享资源(如数据库连接、线程池、配置管理器等),避免重复创建对象,节省系统资源。
1. 单例模式的核心特点
- 唯一实例:单例类只能有一个实例。
- 全局访问点:通过静态方法提供全局访问。
- 私有构造器 :防止外部通过
new
关键字创建实例。 - 线程安全:确保在多线程环境下也能正常工作。
2. 单例模式的实现方式
以下是几种常见的单例模式实现方式:
2.1 饿汉式(Eager Initialization)
- 特点:在类加载时创建实例,线程安全。
- 优点:实现简单,线程安全。
- 缺点:如果实例未被使用,会造成资源浪费。
示例:
java
public class Singleton {
// 在类加载时创建实例
private static final Singleton INSTANCE = new Singleton();
// 私有构造器
private Singleton() {}
// 全局访问点
public static Singleton getInstance() {
return INSTANCE;
}
}
2.2 懒汉式(Lazy Initialization)
- 特点 :在第一次调用
getInstance()
时创建实例。 - 优点:延迟加载,节省资源。
- 缺点:线程不安全,需要额外处理多线程问题。
示例(非线程安全):
java
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton(); // 非线程安全
}
return instance;
}
}
改进(线程安全):
java
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton(); // 线程安全
}
return instance;
}
}
2.3 双重检查锁(Double-Checked Locking)
- 特点:在懒汉式的基础上,通过双重检查减少同步开销。
- 优点:延迟加载,线程安全,性能较好。
- 缺点:实现稍复杂。
示例:
java
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // 第一次检查
synchronized (Singleton.class) {
if (instance == null) { // 第二次检查
instance = new Singleton();
}
}
}
return instance;
}
}
2.4 静态内部类(Static Inner Class)
- 特点:利用类加载机制保证线程安全,同时实现延迟加载。
- 优点:线程安全,延迟加载,实现简单。
- 缺点:无法传递参数。
示例:
java
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
2.5 枚举(Enum)
- 特点:利用枚举的特性实现单例,线程安全,防止反射攻击。
- 优点:线程安全,实现简单,防止反射和序列化破坏单例。
- 缺点:不够灵活(无法延迟加载)。
示例:
java
public enum Singleton {
INSTANCE;
public void doSomething() {
System.out.println("Singleton is working.");
}
}
3. 单例模式的应用场景
- 资源共享 :
- 例如数据库连接池、线程池等。
- 配置管理 :
- 例如全局配置管理器。
- 日志记录 :
- 例如日志记录器。
- 缓存 :
- 例如全局缓存管理器。
4. 单例模式的注意事项
-
线程安全 :
- 确保在多线程环境下单例类的唯一性。
-
反射攻击 :
- 通过反射可以调用私有构造器创建新实例。枚举单例可以防止反射攻击。
-
序列化与反序列化 :
-
反序列化时可能会创建新的实例。可以通过实现
readResolve()
方法解决。 -
示例:
javaprotected Object readResolve() { return getInstance(); }
-
-
延迟加载 :
- 根据需求选择合适的实现方式(如懒汉式、静态内部类等)。
5. 单例模式的优缺点
优点:
- 节省资源:避免重复创建对象。
- 全局访问:方便共享资源。
- 线程安全:通过合理实现可以保证线程安全。
缺点:
- 扩展性差:单例类通常难以扩展。
- 测试困难:单例类的全局状态可能导致测试困难。
- 违反单一职责原则:单例类通常承担过多职责。
6. 总结
单例模式是Java中常用的设计模式,用于确保一个类只有一个实例,并提供全局访问点。根据具体需求,可以选择饿汉式、懒汉式、双重检查锁、静态内部类或枚举等实现方式。在实际开发中,需注意线程安全、反射攻击和序列化等问题。