Java 中的单例模式
简介
在 Java 编程中,单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。单例模式在许多场景下都非常有用,比如配置管理器、日志记录器等,这些场景需要在整个应用程序中共享一个实例。
目录
- 基础概念
- 使用方法
- 常见实践
- 饿汉式单例
- 懒汉式单例
- 双重检查锁单例
- 静态内部类单例
- 枚举单例
- 最佳实践
- 小结
- 参考资料
基础概念
单例模式的核心思想是将类的实例化过程封装起来,使得外部代码无法直接创建该类的实例,而是通过一个公共的静态方法来获取唯一的实例。这个唯一的实例在内存中只有一份,所有对该实例的引用都指向同一个对象。
使用方法
步骤
- 将类的构造函数声明为私有,防止外部类通过
new
关键字创建实例。 - 在类内部创建一个静态的私有成员变量,用于存储唯一的实例。
- 提供一个公共的静态方法,用于获取这个唯一的实例。
常见实践
饿汉式单例
饿汉式单例在类加载时就创建了实例,不管是否需要使用。
public class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() {
}
public static EagerSingleton getInstance() {
return instance;
}
}
懒汉式单例
懒汉式单例在第一次调用 getInstance
方法时才创建实例。
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {
}
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
双重检查锁单例
双重检查锁单例在多线程环境下确保实例的唯一性,同时提高性能。
public class DoubleCheckedLockingSingleton {
private volatile static DoubleCheckedLockingSingleton instance;
private DoubleCheckedLockingSingleton() {
}
public static DoubleCheckedLockingSingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckedLockingSingleton.class) {
if (instance == null) {
instance = new DoubleCheckedLockingSingleton();
}
}
}
return instance;
}
}
静态内部类单例
静态内部类单例利用了类加载机制来确保线程安全。
public class StaticInnerClassSingleton {
private StaticInnerClassSingleton() {
}
private static class SingletonHolder {
private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();
}
public static StaticInnerClassSingleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
枚举单例
枚举单例是最简洁且线程安全的单例实现方式。
public enum EnumSingleton {
INSTANCE;
// 可以在这里添加其他方法和属性
public void doSomething() {
System.out.println("Doing something in EnumSingleton");
}
}
最佳实践
- 线程安全:在多线程环境下,确保单例的创建和使用是线程安全的。可以使用
synchronized
关键字、双重检查锁或者利用类加载机制来实现。 - 性能优化:避免不必要的同步操作,如懒汉式单例在多线程环境下的同步问题,可以通过双重检查锁或者静态内部类单例来优化。
- 防止反序列化破坏单例:如果单例类需要实现
Serializable
接口,需要重写readResolve
方法来防止反序列化时创建新的实例。
protected Object readResolve() {
return getInstance();
}
- 避免反射攻击:虽然反射可以破坏单例的唯一性,但可以通过在构造函数中添加逻辑来防止反射创建新的实例。
private Singleton() {
if (instance != null) {
throw new RuntimeException("Use getInstance() method to get the single instance.");
}
}
小结
单例模式在 Java 编程中是一种非常实用的设计模式,它能够确保一个类只有一个实例,并提供全局访问点。不同的单例实现方式各有优缺点,在实际应用中需要根据具体的需求和场景来选择合适的实现方式。同时,要注意单例模式在多线程环境下的线程安全问题以及可能面临的反序列化和反射攻击等问题。
参考资料
- 《Effective Java》 - Joshua Bloch
- Oracle Java Documentation
- 维基百科 - 单例模式