1.什么是单例模式
单例模式是设计模式的一种,那什么是设计模式呢?
欸问得好,设计模式就是对常见的业务场景总结出来的处理方法,相当于一种“套路”,类似于打王者时候,跟这个英雄对线用连招213比较好,跟那个英雄对线用连招123比较好,嗯…就是这样。
2.如何实现单例模式
实现单例模式,也就是实现单例类有两种方法,首先当我们创建一个正常类的时候,我们可以new无数个这个类的对象且不重复,例如下图:
看到没,student01和student02是不一样的,它们是两个完全不同的对象
但是在单例模式下,也就是单例类,你不管怎么实例化,最终实例化出来的对象完全唯一。
那么如何实现单例类呢?步骤如下:
1.在类中定义一个static修饰的变量就可以保证这个变量全局唯一(单例)
2.构造方法私有化(防止外部new对象)(那怎么外部实例这个类呢?)
3.设置一个get方法取获取对象,用static修饰,这样外部类就可以通过类名.get的方式调用
具体的实现方法有两种:“饿汉模式”和“懒汉模式”,我们下面逐一介绍:
2.1饿汉模式
代码实现:
按上面步骤写就是这样,接下来我们在多线程环境测试一下:
看,是不是外部类无法new新对象,只能用类的静态方法get获取,接下来我们删去new和打印的两行代码,测试十个线程get对象是不是同一个
Look!就是同一个!这个结果我已经测试了六遍了,你不服可以复制一下代码回去自己跑一下嘻嘻
2.2懒汉模式
代码实现(别急有反转):
接下来我们用多线程测试一下:
OK眼尖的大佬已经发现了多线程环境中实例化出来的对象不唯一啊,测试结果与预期不符这叫什么,嗯这就是出现了线程安全问题
问题原因详解:根本原因是cpu调度问题,线程是抢占式执行的,例如现在有两个线程,A和B,当A首先进get方法美滋滋拿到instance后!还没把instance 给store呢,线程B也进来了!由于A还没来及store它拿到的instance,instance此时为空!那么B load 的也是空, 嘿B也能通过if语句,B又get一个instance!问题就出现了…
如何解决:给那段代码加锁,确保A没执行完其他线程例如B不许进来,就好了,如下:
但是,还有个问题:这一加锁,每个线程进来在cpu中都要lock 然后再unlock,效率很低啊,因为这个锁我们只用一次啊,当第一次instance成功store后,后面线程load的都是那个对象,就进不去if从句,所以我们。。。。
再加个判断条件,当instance不为空直接返回就好了,不用进来再加锁再判断,然后发现不为空再返回。
于是,完整代码如下(无反转版):
史称DCL (Double Check Loak)双重检查锁
当然真理解不了就算了,不加,代码也能跑过,随缘。
2.3缘起
那么为什么一个叫饿汉模式一个叫懒汉模式呢,其实看代码就知道了:
饿汉模式中第一步直接就把那个static修饰的变量给实例化了,就像一个饿了很久的流浪汉,库库吃
第二个懒汉模式就是第一步我只声明一下,我懒得实例化,等到后面再说~所以叫懒汉
嗯。。。。。。。。。。。。。。。。。。。。其实我一直觉得好牵强,不如一个叫极简模式一个叫炫技模式(我的评价是)
。。。。。。。
那么好本篇写完了,(好厉害),当然了主播是实力派(OK)(KO)。