设计模式源码git地址:design-pattern-src: 设计模式源码 (gitee.com)
什么是单例模式
使用场景
常见的应用场景
实现套路
八大实现方式
什么是单例模式 单例模式指某个类中只存在一个对象实例,创建对象的,属于创建者模式
使用场景 对于一些频繁创建销毁的对象来说,创建对象耗时或者消耗资源多,工具类对象
常见的应用场景 ①Runtime类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class Runtime { private static Runtime currentRuntime = new Runtime(); public static Runtime getRuntime () { return currentRuntime; } private Runtime () {} }
②数据库连接池
数据库连接是一种数据库资源。数据库软件系统中使用数据库连接池,主要是节省打开或者关闭数据库连接所引起的效率损耗,这种效率上的损耗还是非常昂贵的,因为何用单例模式来维护,就可以大大降低这种损耗
③spring的对象管理默认为单例模式
实现套路 虽然实现方式众多,但核心绕不开两点
1、私有化构造方法,防止外部类去new
2、静态变量定义,保证唯一性
八大实现方式 饿汉两种,懒汉三种,双重检查,静态内部,枚举
饿汉可以理解为:刚加载类就迫不及待创建对象,急
懒汉可以理解为:只有需要的时候才创建对象,不急
1、饿汉式(静态常量) 1 2 3 4 5 6 7 8 9 private EHan1 () {}private final static EHan1 instance = new EHan1();public static EHan1 getInstance () { return instance; }
优点:简单,类装载时加载,避免线程同步问题
缺点:没有达到懒加载,如果没用到,会造成内存浪费
2、饿汉式(静态代码块) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 static { instance = new EHan2(); } private EHan2 () {} private static EHan2 instance;public static EHan2 getInstance () { return instance; }
优缺点相同
3、懒汉式(线程不安全) 1 2 3 4 5 6 7 8 9 10 11 12 private LanHan1 () {}private static LanHan1 instance;public static LanHan1 getInstance () { if (instance == null ) { instance = new LanHan1(); } return instance; }
测试方法相同
优点:简单,起到了懒加载效果,使用对象时才创建,
缺点:线程不安全(只能在单线程下使用),实际开发时不建议
4、懒汉式(线程安全,同步方法) 1 2 3 4 5 6 7 8 9 10 11 12 private LanHan2 () {}private static LanHan2 instance;public static synchronized LanHan2 getInstance () { if (instance == null ) { instance = new LanHan2(); } return instance; }
缺点:每个线程想要获取类的时候,都需要进行getInstance()方法获取,等待时间过长,效率低下,实际开发不建议使用这种方式
5、懒汉式(线程安全,同步代码块) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 private LanHan3 () {}private static LanHan3 instance;public static LanHan3 getInstance () { if (instance == null ) { synchronized (LanHan3.class) { instance = new LanHan3(); } } return instance; }
缺点:对于效率低的问题,放入了代码块中执行,实际上不能起到线程同步的问题,实际开发中不能使用
6、双重检查(推荐) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 private static volatile DoubleCheck instance;private DoubleCheck () {}public static DoubleCheck getInstance () { if (instance == null ) { synchronized (DoubleCheck.class) { if (instance == null ) { instance = new DoubleCheck(); } } } return instance; }
优点:懒加载,线程安全,保证效率。推荐使用
两个判断的意义 :第一个保证效率,如果有实例那么直接返回
volatile:保证可见性,防止小概率指令重排造成的失败
第二个为了保证线程安全,不然可能会出现多线程多实例的情况
7、静态内部类(推荐) 1 2 3 4 5 6 7 8 9 private NeiBu () {}private static class getInstanceClass { private static final NeiBu INSTANCE = new NeiBu(); } public static NeiBu getInstance () { return getInstanceClass.INSTANCE; }
JVM在装载类的时候,线程是安全的,使用了类装载机制
在加载NeiBu类时,内部类getInstanceClass不会被加载,只有在调用getInstance的时候才会进行加载
优点:懒加载,线程安全。推荐使用
8、枚举类(推荐) 1 2 3 4 5 6 enum instance { INSTANCE; public void say () { System.out.println("ok" ); } }
测试代码
1 2 3 instance instance1 = singleton.instance.INSTANCE; instance instance2 = singleton.instance.INSTANCE; System.out.println(instance1 == instance2);
借助jdk5提出的枚举类来实现到单例模式,不仅能避免同步问题,还能防止反序列化创建对象。推荐使用