02-设计模式——单例模式
设计模式——单例模式
通过
javap -v -p xxxx.class
可以查看对应字节码信息
模式定义
保证一个类只有一个实例,并且提供一个全局访问点
场景:
重量级的对象,不需要多个实例,如线程池,数据库连接池
懒汉模式
1.懒汉模式:延迟加载,只有在真正使用的时候,才开始实例化
- 线程安全问题
- double check 双重检查,加锁优化
- 编译器(JIT),CPU有可能对指令进行重排序,导致使用到尚未初始化的实例,可以通过添加volatile关键字进行修饰,对于volatile修饰的字段,可以防止指令重排
/** * @program: DesignPatterns * @description: 懒汉单例模式 * @author: Coder_Pan * @create: 2022-04-12 18:48 **/ public class LazySingletonTest { public static void main(String[] args) { /** * 第一个线程开启 */ new Thread( () -> { LazySingleton instance = LazySingleton.getInstance(); System.out.println(instance); }).start(); /** * 第二个线程开启 * * 运行会发现两个线程中创建的对象不一致 * */ new Thread( () -> { LazySingleton instance = LazySingleton.getInstance(); System.out.println(instance); }).start(); /** * 单个线程下一切ok */ // LazySingleton instance = LazySingleton.getInstance(); // LazySingleton instance1 = LazySingleton.getInstance(); // System.out.println(instance == instance1); } } /** * 创建懒汉实例 */ class LazySingleton { /** * 加上volatile防止重排序,规定字节码层面顺序为123 */ private volatile static LazySingleton instance; private LazySingleton(){ } public static LazySingleton getInstance() { /** * 如果实例为空,才创建 * synchronized =》 加锁,保证只有一个实例 */ if (instance == null) { /** * 当对象为空时才进行加锁 * * 防止重复加锁操作 */ synchronized (LazySingleton.class){ if (instance == null) { instance = new LazySingleton(); //字节码层 //1.分配空间 //2.初始化 //3.引用赋值 } } } return instance; } // public synchronized static LazySingleton getInstance() { // /** // * 如果实例为空,才创建 // * 需要在LazySingleton的getInstance上加上synchronized才能保持多个线程下实例对象的一致性,这个方式会造成资源浪费,重复加锁 // * synchronized =》 加锁,保证只有一个实例 // */ // if (instance == null) { // // instance = new LazySingleton(); // } // return instance;va // } }
饿汉模式
类加载的初始化阶段就完成了实例的初始化。
本质上就是借助与jvm类加载机制,保证实例的唯一性
类加载过程:
- 加载二进制数据到内存中,生成对应的Class数据结构
- 连接:a、验证 ,b、准备(给类的静态成员变量赋默认值),c、解析
- 初始化:给类的静态变量赋初值
只有在真正使用对应的类时,才会触发初始化 如(当前类时启动类,即main函数所在类,直接进行new操作,访问静态属性,访问静态方法,用反射访问类,初始化一个类的子类等)
/** * @program: DesignPatterns * @description: 饿汉单例模式 * @author: Coder_Pan * @create: 2022-04-12 19:32 **/ public class HungrySingletonTest { public static void main(String[] args) { System.out.println("饿汉单例模式...HungrySingleton"); HungrySingleton instance = HungrySingleton.getInstance(); HungrySingleton instance1 = HungrySingleton.getInstance(); System.out.println(instance == instance1); } } /** * 饿汉模式 ⬇ */ class HungrySingleton{ /** * 静态属性在何时实例化 */ private static HungrySingleton instance = new HungrySingleton(); private HungrySingleton(){ } /** * 公开的方法,对外提供访问 * @return */ public static HungrySingleton getInstance() { return instance; } }
静态内部类
- 本质上是利用类的加载机制来保证线程安全
- 只有在实际使用的时候,才会触发类的初始化,所有页式懒加载的一种形式
/** * @program: DesignPatterns * @description: 静态内部类实现方式 * @author: Coder_Pan * @create: 2022-04-12 19:56 **/ public class InnerClassSingletonTest { public static void main(String[] args) { InnerClassSingleton instance = InnerClassSingleton.getInstance(); InnerClassSingleton instance1 = InnerClassSingleton.getInstance(); System.out.println(instance == instance1); //创建线程 new Thread( () -> { InnerClassSingleton instance2 = InnerClassSingleton.getInstance(); System.out.println("Thread - 1" + instance2); }).start(); new Thread( () -> { InnerClassSingleton instance2 = InnerClassSingleton.getInstance(); System.out.println("Thread - 2" + instance2); }).start(); } } class InnerClassSingleton{ /** * InnerClassHolder => 静态内部类 * 基于jvm实现的懒加载模式 * * 只有在调用getInstance()方法的时候才会导致静态内部类的初始化 * 进而才会使InnerClassSingleton初始化 */ private static class InnerClassHolder{ private static InnerClassSingleton instance = new InnerClassSingleton(); } private InnerClassSingleton(){ } public static InnerClassSingleton getInstance(){ return InnerClassHolder.instance; } }
反射攻击
/** * 反射攻击 * * 通过反射创建实例,单例模式就失效了 */ try { Constructor<InnerClassSingleton> declaredConstructor = InnerClassSingleton.class.getDeclaredConstructor(); declaredConstructor.setAccessible(true); InnerClassSingleton instance = declaredConstructor.newInstance(); InnerClassSingleton instance1 = InnerClassSingleton.getInstance(); System.out.println("反射机制创建单例模式"); System.out.println(instance == instance1); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); }
class InnerClassSingleton{ /** * InnerClassHolder => 静态内部类 * 基于jvm实现的懒加载模式 * * 只有在调用getInstance()方法的时候才会导致静态内部类的初始化 * 进而才会使InnerClassSingleton初始化 */ private static class InnerClassHolder{ private static InnerClassSingleton instance = new InnerClassSingleton(); } private InnerClassSingleton(){ /** * 防止反射攻击,使单例模式不被破坏 */ if (InnerClassHolder.instance != null){ throw new RuntimeException(" 单例模式下不允许多个实例! "); } } public static InnerClassSingleton getInstance(){ return InnerClassHolder.instance; } }
如果想实现数据的一个持久化的操作,就需要这个类进行序列化,这样jvm才会对其处理
即implements Serializable,开启序列化
源码中的应用
java.lang.Runtime ProxyFactoryBean DefaultSingletonBeanRegistry ReactiveAdapterRegistry TomcatURLStreamHandlerFactory //反序列化指定数据源 java.util.Currency
posted on 2022-04-12 21:28 JavaCoderPan 阅读(16) 评论(0) 编辑 收藏 举报 来源
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南