今天主要来介绍注册式单例模式
注册式单例包括两种:一种是枚举式单例,一种是容器式单例(springIoc模块中大量用到此模式)
先来介绍枚举式单例,问题:为什么枚举式一定可以保证单例?
我新建了一个单例类来测试解决该问题
而后我通过Jad反编译可以看到
1、首先它并没有一个无参的构造方法,在整个程序中,不管怎么序列化,程序启动时只会初始化该对象一次。
2、其次获取该实例的INSTANCE实际上是一个饿汉式单例,属于线程安全范畴。
到此为止,保证单例性质解决了,但是怎么保证被反序列化暴力破解呢?
其实在ObjectInputStream.readObjecg() 方法中 进入到readObject0()方法内
在我们进入到 readEnum() 方法内可以发现
实际上是通过一个类名加上一个枚举的名字,通过这两个唯一值去确定这个枚举,显然我们的JVM中肯定只会被加载一次。
序列化方法看来是行不通了,那么能否通过反射方式去破坏该单例呢?
结果得知: 我们通过反射方式去创建该对象但是却显示无法被反射
从JDK层面就为枚举不被序列化和反射破坏。
接下来介绍另外一种单例方式:容器式单例 springIoc模块 是采用这种方式
但是不可避免会带来线程安全问题
可以看到创建了N个对象 解决方案:
实际上我们还是可以采用同步锁的方式 就可以完美解决该问题了