27 | 单例模式:如何创建单一对象优化系统性能?
该思维导图由 AI 生成,仅供参考
什么是单例模式?
饿汉模式
- 深入了解
- 翻译
- 解释
- 总结
单例模式是一种常用的设计模式,用于确保一个类仅创建一个实例,并提供一个全局访问点。本文介绍了单例模式的基本概念和懒汉模式的实现方式。懒汉模式通过懒加载方式,在系统使用到类对象时才将实例加载到堆内存中。然而,在多线程情况下可能会出现实例化多个类对象的问题。文章详细介绍了使用Synchronized同步锁和Double-Check的方式来解决多线程下的单例实例化问题,并讨论了Happens-Before规则和重排序的影响。此外,文章还介绍了通过内部类实现的懒汉模式,避免了多线程下重复创建对象的情况。总结了单例模式的两种实现方式:饿汉模式和懒汉模式,并提出了根据需求选择合适的实现方式的建议。整体而言,本文深入浅出地介绍了单例模式的实现方式,为读者提供了全面的技术知识和实践经验。
《Java 性能调优实战》,新⼈⾸单¥59
全部留言(41)
- 最新
- 精选
- Loubobooo使用枚举来实现单例模式,具体代码如下:public class SinletonExample5 { private static SinletonExample5 instance = null; // 私有构造函数 private SinletonExample5(){ } public static SinletonExample5 getInstance(){ return Sinleton.SINLETON.getInstance(); } private enum Sinleton{ SINLETON; private SinletonExample5 singleton; // JVM保证这个方法只调用一次 Sinleton(){ singleton = new SinletonExample5(); } public SinletonExample5 getInstance(){ return singleton; } } }
作者回复: 很赞!这是一种懒加载模式的枚举实现。
2019-07-23755 - 豆泥丸最安全的枚举模式,反射和序列化都是单例。
作者回复: 对的,我们之前序列化优化这一讲中的问答题就是与枚举实现单例相关,《Effective Java》作者也是强烈推荐枚举方式实现单例。
2019-07-23430 - Jxin1.可能大部分同学都知道,但为了少部分同学,我在老师这个单例上补个点。其它线程空指针异常确实是指令重排导致的,但其原因还有一个。加锁并不能阻止cpu调度线程执行体,所以时间片还是会切的(假设单核),所以其他线程依旧会执行锁外层的if(),并发情况下就可能拿到仅赋值引用,未在内存空间存储数据的实例(null实例),进而空指针。 2.给老师的代码补段骚的: // 懒汉模式 + synchronized 同步锁 + double-check public final class Singleton { private static validate Singleton instance = null;// 不实例化 public List<String> list;//list 属性 private Singleton(){ list = new ArrayList<String>(); }// 构造函数 public static Singleton getInstance(){// 加同步锁,通过该函数向整个系统提供实例 Singleton temp = instance; if(null == temp){// 第一次判断,当 instance 为 null 时,则实例化对象,否则直接返回对象 synchronized (Singleton.class){// 同步锁 temp = instance; if(null == temp){// 第二次判断 temp = new Singleton();// 实例化对象 instance = temp; } } } return instance;// 返回已存在的对象 } } 用临时变量做方法内数据承载(相对于validate修饰的属性,可以减少从内存直接拷贝数据的次数),最后用instance接收临时变量时,因为是validate修饰,所以也不会有指令重排。所以前面临时变量的赋值操作已经完成,这样instance就必然是赋值好的实例。(如有错误请老师指出,仅个人理解的骚操作) 3.极限编程试试就好,业务代码还是尽量优先保证可读性,只有在有性能需求时再采用影响可读性的性能优化。我的这种骚写法和老师的内部类,这种看起来需要想那么一下的东西尽量避免,简单才是王道。
作者回复: 虽然有点绕,还是值得表扬的。我们还是鼓励简单易懂的编程风格。
2019-07-23912 - 行者枚举也是一种单例模式,同时是饿汉式。 相比Double Check,以内部类方式实现单例模式,代码简洁,性能相近,在我看来是更优的选择。
作者回复: 也可以使用枚举实现懒汉模式,可以根据本讲中的使用内部类方式实现懒加载。
2019-07-2310 - -W.LI-枚举底层实现就是静态内部类吧
作者回复: 对的,枚举是一种语法糖,在Java编译后,枚举类中的枚举会被声明为static,接下来就跟我们文中讲的一样了。
2019-07-238 - 我又不乱来枚举天生就是单例,但是不清楚这么实现。 注册式单例,spring应该是用的这种。这个也不太清楚,超哥有机会讲一下spring的实现方式和枚举方式实现的单例。谢谢😁
作者回复: Spring中的bean的单例虽然是一种单例效果,但实现方式是通过容器缓存实现,严格来说是一种享元模式。
2019-07-236 - 张三丰如果把这个成员变量的static去掉,在多线程情况下就可能创建多个实例,单线程没问题。老师,这么理解没问题吧? // 饿汉模式 public final class Singleton { private Singleton instance=new Singleton();// 自行创建实例 private Singleton(){}// 构造函数 public static Singleton getInstance(){// 通过该函数向整个系统提供实例 return instance; } }
作者回复: 这个没法调用的哦,静态方法无法调用非静态成员变量。
2019-10-225 - Zed容器类管理 class InstanceManager { private static Map<String, Object> objectMap = new HashMap<>(); private InstanceManager(){} public static void registerService(String key,Object instance){ if (!objectMap.containsKey(key)){ objectMap.put(key,instance); } } public static Object getService(String key){ return objectMap.get(key); } }
作者回复: Spring中bean的单例就是使用容器来实现的,便于管理。
2019-07-2334 - 我知道了嗯枚举实现单例
作者回复: 对的
2019-07-233 - 风轻扬老师。枚举单例可以防止反射攻击、序列化攻击。但是,我们要获取的实例化对象怎么防止暴力反射呢?我现在的做法是在实例化对象的私有构造器中加判断,如果暴力反射,直接抛出运行异常。老师有没有好的办法?百思不得其解
作者回复: 可以通过反序列化对象白名单来控制运行反序列哪些对象,这种方式需要重写resolveClass 方法,具体参考09讲: 极客时间版权所有: https://time.geekbang.org/column/article/99774
2019-09-111