单例模式——小白总结

单例模式——小白总结

设计模式(Design pattern),提供了在软件开发过程中面临的一些问题的最佳解决方案,是Java开发者必修的一门课程。主要分创建型模式、结构型模式和行为型模式。其中接下来我们要写的是单例模式,属于创建型模式。

单例模式(Singletom Pattern)是指确保一个类在任何情况下都绝对只有一个实例,并提供全局访问点。

关键词:隐藏其所有的构造方法 属于创建型模式 确保任何情况下都绝对只有一个实例

应用:ServletContext、ServletConfig、ApplicationContext、DBPool

常见写法:饿汉式单例、懒汉式单例、注册式单例、ThreadLocal单例

1、饿汉式单例

类加载时就会创建。不管你用不用,都进行初始化。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w6zggRtU-1627743930051)(https://i.loli.net/2021/07/31/Kv67A95sSoaXh4m.png)]

加静态代码块的:

image-20210731213807359

注意点:final关键字,可以防止通过反射机制对你私有化的构造方法覆盖。

优点:够安全,不管你是否多线程,都能保证你创建的是同一个对象。

缺点:每次初始化的时候就创建对象,如果成千上万个线程调用,会造成内存的浪费。

2、懒汉式单例

顾名思义,只有调用时才创建

1、双重检测锁

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KE42aEqU-1627743930063)(https://i.loli.net/2021/07/31/jaGBJp935PQ4gNe.png)]

说明:不在方法外面加锁,在方法内部加,也是优化性能

最外层循环的作用:过滤掉大部分线程,不走同步方法,提高

volatile关键字的作用:解决指令重排问题(2、3顺序会颠倒)

​ CPU执行时会转换成JVM指令执行

​ 1、分配内存给这个对象

​ 2、初始化对象

​ 3、将初始化好的对象和内存地址建立关联、赋值

​ 4、用户初次访问

2、静态内部类

image-20210731220509157

原理:巧妙利用类的加载机制:内部类先加载,LazyHolder里面的逻辑需要外部方法调用时才执行,属于JVM底层的实现逻辑。

优点:没用到synchronized,保证了效率。

缺点:和饿汉式单例一样,不能控制实例初始化。

构造方法里面加判断,避免反射攻击,其他单例也一样。

接下来我们看一下每加判断和加了判断的反射攻击

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wKLdhV7l-1627743930074)(https://i.loli.net/2021/07/31/vWo13EUtsVDcA2H.png)]

运行结果:

image-20210731222010003

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DRsDy1zQ-1627743930079)(https://i.loli.net/2021/07/31/5yFabWui7rO2Jhp.png)]

说明:通过构造方法反射调用单例,他会得到不一样的对象,不符合单例模式。

3、注册式单例

将每一个实例都缓存到统一的容器中,使用唯一标识获取实例

1、枚举式单例(推荐)最安全

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xFarW80K-1627743930080)(https://i.loli.net/2021/07/31/IMVcmtEK4AsF6Dd.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wILO719p-1627743930083)(https://i.loli.net/2021/07/31/noNIExVYwDCU4QX.png)]

可以防止序列化攻击和反射攻击

image-20210731173205321

从JDK层面就为枚举不被序列化和反射破坏做了判断

通过看他的反编译 属于饿汉式单例,安全性没得说

image-20210731173835487

2、容器单例

spring中实现的单例,优点方面管理懒加载,缺点:需要加synchronized关键字,不然getBean方法不安全(如果多线程,多并发的情况下)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WmsTs1Mj-1627743930087)(https://i.loli.net/2021/07/31/MUyD52Vu3GYChaE.png)]

4、ThreadLocal单例

应用:使用ThreadLocal来实现多数据源动态切换(数据源路由)

image-20210731225310990

线程伪安全,在线程里面安全

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jwW0tjwV-1627743930092)(https://i.loli.net/2021/07/31/Zt3EfgHhWMXjUuK.png)]
结果:
image-20210731225434001

说明:他是通过对应的线程作为key,获取值,每一个key都是线程安全的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vU6c2v19-1627743930097)(https://i.loli.net/2021/07/31/3ofzkYM1OEI9XrR.png)]

5、序列化单例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CQYOr8d1-1627743930098)(https://i.loli.net/2021/07/31/hUjuIiKW1PVsZor.png)]
测试:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SqQQa0zq-1627743930099)(https://i.loli.net/2021/07/31/J1x5Vqor6YmsnNE.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yVDnuxi7-1627743930101)(https://i.loli.net/2021/07/31/kcHAnSMKiyN2BxR.png)]

不重写readObject()方法会造成两次创建对象不一致的结果

说明:他会先去判断有没有readObject方法

image-20210731230010889

image-20210731230146493

单例模式的优缺点:

优点:1、在内存中只有一个实例,避免了内存开销

​ 2、可以避免对资源的多重占用

​ 3、设置全局访问点,严格控制访问

缺点:1、没有接口,扩展困难

​ 2、如果要扩展单例对象,只能修改代码,不满足开闭原则的设计思路

总结、

1、私有化构造器

2、保证线程安全

3、延迟加载

4、防止序列化和反序列化破坏单例

​ 2、可以避免对资源的多重占用

​ 3、设置全局访问点,严格控制访问

缺点:1、没有接口,扩展困难

​ 2、如果要扩展单例对象,只能修改代码,不满足开闭原则的设计思路

总结、

1、私有化构造器

2、保证线程安全

3、延迟加载

4、防止序列化和反序列化破坏单例

5、防止反射攻击

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值