欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 名人名企 > 设计模式-单例模式

设计模式-单例模式

2025/5/22 13:55:55 来源:https://blog.csdn.net/woai3364/article/details/146607483  浏览:    关键词:设计模式-单例模式

单例模式(Singleton Pattern)是一种创建型设计模式,其核心目标是确保一个类只有一个实例,并提供全局访问点。

单例模式的核心实现要点

  1. 私有构造函数:防止外部直接通过 new 创建实例。
  2. 静态实例:保存类的唯一实例。
  3. 全局访问点:提供获取实例的静态方法。

1、饿汉式

特点:类加载时直接初始化实例,线程安全,但可能浪费资源。

 /*** 饿汉式单例* 优点:实现简单,线程安全* 缺点:类加载时就初始化实例,可能浪费内存*/public class EagerSingleton {// 静态常量直接初始化实例,保证线程安全private static final EagerSingleton INSTANCE = new EagerSingleton();// 私有构造函数,防止外部实例化private EagerSingleton() {}// 全局访问点public static EagerSingleton getInstance() {return INSTANCE;}}
2、懒汉式

特点:延迟加载实例,但是需要通过同步锁保证线程安全(效率低)。

/*** 懒汉式单例(同步方法)* 优点:延迟加载,节省资源* 缺点:同步锁导致性能下降*/
public class LazySingleton {private static LazySingleton instance;// 私有构造函数private LazySingleton() {}// 同步方法保证线程安全,但每次调用都加锁public static synchronized LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}
}
3、双重校验

特点:在懒汉式的基础上,降低锁的粒度,提高效率

/*** 双重检查锁定单例* 特点:在懒汉式的基础上,降低锁的粒度,减少锁的等待时间*/
public class Singleton_03 {// volatile 禁止指令重排序,保证可见性private static volatile Singleton_03 instance;private Singleton_03() {}public static Singleton_03 getInstance() {// 第一次检查(无锁)if (instance == null) {synchronized (Singleton_03.class) {// 第二次检查(有锁)if (instance == null) {instance = new Singleton_03();/** new 操作分为三步:* 1. 分配内存空间* 2. 初始化对象* 3. 将引用指向内存地址* volatile 防止指令重排序到1 → 3 → 2 的情况*/}}}//如果没有volatile 在多线程环境下会返回一个次品对象return instance;}
}
4、静态内部类

特点:利用类加载机制保证线程安全,天然支持延迟加载。

/*** 静态内部类单例* 优点:线程安全、延迟加载、无锁高效* 缺点:无法通过参数初始化实例*/
public class InnerClassSingleton {// 私有构造函数private InnerClassSingleton() {}// 静态内部类持有实例private static class SingletonHolder {private static final InnerClassSingleton INSTANCE = new InnerClassSingleton();}// 全局访问点public static InnerClassSingleton getInstance() {return SingletonHolder.INSTANCE; // 首次调用时加载内部类}
}
5、枚举

特点:简洁、线程安全,天然防御反射和序列化攻击(推荐方式)。

/*** 枚举单例(推荐)* 优点:天然线程安全,防御反射和序列化攻击* 缺点:无法延迟加载*/
public enum EnumSingleton {INSTANCE; // 枚举常量即为单例实例public static EnumSingleton getInstance(){return INSTANCE;}
}

反射的核心功能

  1. 运行时获取类信息:无需提前知道类名,动态加载类。
  2. 操作对象:动态创建对象、调用方法、访问字段。
  3. 突破访问限制:访问私有(private)成员。
1. 防御反射攻击
  • 问题:通过反射调用私有构造函数可以创建新实例。
  • 解决方案:在构造函数中检查实例是否已存在,若存在则抛出异常。
2. 防御序列化攻击
  • 问题:反序列化会生成新对象。
  • 解决方案:实现 readResolve() 方法返回已有实例。
反射对于单例的破坏
/*** 反射对于单例的破坏*/
public class Test_Reflect {public static void main(String[] args) throws Exception {Class<InnerClassSingleton> clazz = InnerClassSingleton.class;Constructor<InnerClassSingleton> constructor = clazz.getDeclaredConstructor();constructor.setAccessible(true);InnerClassSingleton instance = constructor.newInstance();InnerClassSingleton instance2 = constructor.getInstance();System.out.println(instance == instance2);}
}false
解决方式

在构造器添加一个判断语句

 // 私有构造函数private InnerClassSingleton() {// 防御反射攻击if (SingletonHolder.INSTANCE != null) {throw new RuntimeException("单例对象已存在!");}}
序列化对于单例的破坏
public class Test_Serializable {@Testpublic void test() throws Exception{//序列化对象输出流ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("tempFile.obj"));oos.writeObject(InnerClassSingleton.getInstance());//反序列化对象输入流File file = new File("tempFile.obj");ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));InnerClassSingleton instance = (InnerClassSingleton) ois.readObject();System.out.println(instance);System.out.println(InnerClassSingleton.getInstance());System.out.println(instance == InnerClassSingleton.getInstance());}
}
//输出
com.pgs.singleton.demo04.Singleton_04@3c9d0b9d
com.pgs.singleton.demo04.Singleton_04@6dbb137d
false
解决方式

只需要在单例类中定义 readResolve 方法,就可以解决序列化对于单例的破坏

   // 防止反序列化破坏单例private Object readResolve() {return SingletonHolder.INSTANCE;}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词