设计模式(一) 单例模式
核心作用:
保证一个类只有一个实例,并且提供一个访问该实例的全局访问点
常见应用场景:
单例模式的优点:
- 由于单例模式只生成一个实例,减少了系统的开销,当一个对象的产生需要比较多的资源师,如:读取配置,产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决
- 单例模式可以在系统设置全局的访问点,优化环共享资源访问,例如可以设计一个单例类负责所有数据表的映射处理
常见的五种单例模式实现方式:
- 饿汉式(线程安全,调用效率高,不能延时加载)
解释:饿汉式单例代码中,static变量会在类装载是初始化,此时也不会涉及多个线程对象访问该对象的问题。虚拟保证只会装载一次该类,肯定不会发生并发访问的问题。因此不需要synchronized关键字
问题:如果只是加载本类,而不是要调用getInstance(),甚至永远没有调用,则会造成资源浪费
package com.lp.singleton; /*测试饿汉式单例模式*/ /*当类实例化的*/ public class SingletonDemo1 { // ctrl + m 快捷键 优化界面 // 重点:类初始化时立即加载 private static SingletonDemo1 instance = new SingletonDemo1(); //这个函数规定了外部不能实例化这个类的对象 private SingletonDemo1(){ } //方法没有同步,调用效率高 public static SingletonDemo1 getInstance(){ return instance; } }
- 懒汉式(线程安全,调用效率不高,可以延时加载)
问题:资源利用率高了,但是,每次调用getInstance方法都要同步,并发效率低
package com.lp.singleton; /*测试懒汉式单例模式*/ public class SingletonDemo2 { // ctrl + m 快捷键 优化界面 // 重点:类初始化时不加载 private static SingletonDemo2 s; //这个函数规定了外部不能实例化这个类的对象 private SingletonDemo2(){ } //方法同步,调用效率低 public static synchronized SingletonDemo2 getInstance(){ if(s == null){ s = new SingletonDemo2(); } return s; } }
- 双重检测锁式(由于JVM底层内部模型原因,偶尔会出问题,不建议使用)
package com.lp.singleton; /*这个模式不建议用*/ public class SingletonDemo3 { private static SingletonDemo3 instance = null; public static SingletonDemo3 getInstance(){ if(instance == null){ SingletonDemo3 sc ; synchronized(SingletonDemo3.class){ sc = instance; if(sc == null){ synchronized(SingletonDemo3.class){ if(sc == null){ sc = new SingletonDemo3(); } } instance = sc; } } } return instance; } private SingletonDemo3(){ } }
- 静态内部类式(线程安全,调用效率高 , 可以延时加载)
要点:1:外部类没有static属性,则不会像饿汉式那样立即加载对象
2:只有真正调用getInstance() ,才会加载静态内部类,加载类时线程是安全的,instance是static final类型,保证了内存中只有这样一个实例存在,而且只能被赋值一次,从而保证了线程安全性.
3:兼备了并发高效调用和延迟加载的优势!
package com.lp.singleton; //集合了线程安全 高效调用 延时加载 三个有点 public class SingletonDemo4 { private static class SingletonClassInstance{ private static final SingletonDemo4 instance = new SingletonDemo4(); } private SingletonDemo4(){ } public static SingletonDemo4 getInstance(){ return SingletonClassInstance.instance; } }
- 枚举单例(线程安全,调用效率高,不能延时加载 )
优点: 1:实现简单
2:枚举本身就是单例模式,由JVM从根本上提供保障!避免通过反射和反序列化的漏洞
package com.lp.singleton; /*测试枚举式实现单例模式*/ /*唯一缺点:没有延时加载的效果*/ /*防止反射和发序列化漏洞*/ public enum SingletonDemo5 { //这个枚举元素,本身就是单例对象! INSTANCE; //添加自己需要的操作 public void singletionOperation(){ } }
如何选用:
--单例对象 占用资源 少,不需要 延时加载:
- 枚举式 好于 饿汉式
--单例对象 占用资源 大,需要 延时加载:
- 静态内部类 好于 懒汉式