你的单例模式真的足够安全吗?

本文探讨了单例模式在多线程环境下可能遭遇的安全问题,尤其是通过反射机制破坏单例的唯一性。尽管一些措施如私有构造器和双重检查锁定(DCL)被用来确保单例,但反射和构造器的非原子性操作仍可能导致多个实例的创建。通过实例代码展示了如何利用反射绕过私有构造器,强调了单例模式在某些情况下的不安全性。文章最后提到了使用枚举类型作为单例实现的更安全方法,并提醒开发者在使用单例时需谨慎。
摘要由CSDN通过智能技术生成

曾经有老师们教过一种方法能够很好的去避免多线程申请单例模式创建一个实例对象的时候创建出多个不同的对象。而包括阿里巴巴的代码业务处理方式推荐清单也明码标价是这样。但是辩证法却无处不在,正所谓魔高一尺道高一丈,总有一些杠精喜欢钻牛角尖,打官司里叫做钻法律空子,互联网里叫做黑客。从比较深层的机制来讲,我们往往可以通过反射机制的一系列“反人类”操作实现对代码安全度的破坏!

相信大家的老师们曾经都是这样教学的,对吧?

没错这样子确实能够规避错误某一方面不需要领略synchronized那种烂番茄低下的效率,一方面帮我们维护了单例模式的英雄本色。好,下面就是破坏!

首先,无论如何,new DCLSingleton()这个操作不是原子性的,也就是说new方法的三要素并非不可拆分,因此就留给反射以可趁之机。这三要素分别是:

1.分配内存空间

2.执行构造方法,初始化对象

3.把对象指向这个空间

那么让我们看看下面的手段:

这段代码说明了些什么,我们利用这个类对象的反射方法可以直接无视构造方法的私有权限直接访问获取到一个鲜活的对象(declared构造器可以访问到私有)。同样地通过爆破手段设置为可见并重新实例化依旧可以创造出新的不同于源代码静态方法getInstance()得到的实例对象从而破坏懒汉式单例原则。

有人说好!既然这样,那我就再构造方法里面在加写代码来预防就好,比如:

这样子的话就不能够通过“偷渡”反射构造的手段来“偷对象”了,是吧?呵呵,你又错了!我只需要把main里面的第一种取值方式取消掉,那么就不能够导致lazyman不为空。不信试试!

 有人会认为直接在属性中添加boolean值使构造器一旦被执行,就让boolean值取反,在取反条件下直接抛出一个我们编写好的异常就行(或者默认异常)。那么你又错了!请看:

 你以为黑客难道就不可以使用爆破域的方式来修正boolean值了吗?结局这不还是一样!

种种这一切都是单例不安全的体现,所以在使用的时候大家要小心哦!至于什么是最安全的单例模式,请看这篇文章:最安全的单例模式-枚举_素净小凡人的博客-CSDN博客_绝对安全的单例模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值