小白谈谈单例模式

概念

通过单例模式创建类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类可以直接访问,不需要实例化对象。


介绍

意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点
主要解决:一个全局使用的类频繁地创建和销毁
何时使用:当你想控制实例数目,节省系统资源的时候
如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建

优点
1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
2、避免对资源的多重占用(比如写文件操作)。

缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

使用场景:
1、要求生产唯一序列号
2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。


实现方式

(一)饿汉式(可行的)
使用最广泛
类加载到内存后,就会实例化一个单例,jvm保证线程安全
唯一的缺点:不管是否使用,都会在类加载的时候完成实例化

实现代码:
在这里插入图片描述

(二) 饿汉式(可行的)
与一的原理一样,写法方式不同

实现代码:
在这里插入图片描述
(三)懒汉式(不可行的)
虽然达到了按照需求再进行初始化的目的,但是会造成线程不安全

举例说明:比如第一个实例在调用getInstance()的时候,还没执行到new Mgr03那一步,第二个实例也进入了getInstance()的方法,那么就会创建了两个Mgr03对象,所以会造成线程不安全

实现代码:
在这里插入图片描述
实验的效果:
在这里插入图片描述
(四)懒汉式(不可行的)
在三的基础上,通过使用synchronized解决线程不安全的问题,但是这种方式会带来效率下降

实现代码:
在这里插入图片描述
实验结果:
在这里插入图片描述
(五)懒汉式(不可行的)
第四中方式实现的时候,效率下降,因此试图通过在方法中加锁,通过减少同步代码块的方式提高效率,然而还是不可行的,还是会出现线程不安全的问题。

失败的案例:第一个线程在调用getInstance()方法的时候,判断INSTANCE为空,而还没继续往下执行,第二个线程也调用getInstance()方法,也判断INSTANCE为空,并且继续往下执行,创建了一个实例,然后释放锁,第一个线程获得锁之后,又创建了一个新的实例,这就违背了单例

实现代码:
在这里插入图片描述
实现结果:
在这里插入图片描述

(六)懒汉式(可行的)
在五的基础上,进一步改进,于是有了双重判断方式,这种方式大大提高了效率,而且实现了线程安全,外层的判断不可删除,若是删除了,每一次调用方法的时候都要加锁,防止多余的锁
在这里插入图片描述
实验结果:
在这里插入图片描述

(七)静态内部类的方式(可行的)
通过JVM保证单例,加载外部类的时候不会加载内部类,在加载Mgr07类的时候,内部类Mgr07Holder是不会被加载的,所以当要调用getInstance()方法的时候才会把Mgr07Holder加载,从而实现懒加载,保证线程安全是通过jvm,jvm在加载类的时候只加载一次,所以Mgr07,Mgr07Holder也是只加载一次,因此Mgr07Holder中的INSTANCE永远只有一个对象

实现代码:
在这里插入图片描述
实验结果:
在这里插入图片描述
(八)通过枚举类实现(可行的)
不仅可以解决线程同步,还可以防止反序列化
枚举类没有构造方法,所以就算有Mgr08的class,也无法实例化Mgr08的对象,它的反序列化只是枚举类中INSTANCE中的这个值,所以所有Mgr08类中的INSTANCE都是同一个对象

实现代码:
在这里插入图片描述

实验结果:
在这里插入图片描述

本文参考:https://www.runoob.com/design-pattern/singleton-pattern.html
本文的代码:https://pan.baidu.com/s/1WwPej6zPPiF5co24Enymtw
提取码:2bzu

发布了48 篇原创文章 · 获赞 0 · 访问量 670

猜你喜欢

转载自blog.csdn.net/weixin_44943485/article/details/105120614