单例模式

单例模式 Singleton Pattern

确保一个类只有一个实例,并对外提供统一访问方式

 

目前主流的单例模式有两种:

  饿汉模式:类被加载的时候就立即初始化并创建唯一实例

  懒汉模式:在被客户端首次调用的时候才创建唯一实例 

    加入双重检查锁机制的懒汉模式能确保线程安全

 

//---------------

注意:懒汉模式,在创建唯一实例也有需要注意的点。

在new一个对象的时候一般有三个步骤

1.分配对象内存空间

2.初始化对象

3.设置instance指向刚匹配的内存地址,此时instance ! = null

这三个步骤并不是完全按照顺序执行的。所以当懒汉模式的第一个线程进入的时候发现对象是空的开始执行new对象,当new对象步骤执行1  -》 3  -》2的时候,

在3的时候对象的内存地址分配好后,此时并没有为对象初始化。此时进入第二个线程在判断的时候发现已在内存地址中获取到对象直接返回(未初始化)的对象。

那对项目的影响是不容小觑的。

 

//-----------------------

烂大街的单例模式真的足够安全吗(private真的private吗)?

单例模式中将关键的方法和对象private起来,但是这真的安全吗。当我们反射获取到Class对象后依旧可获取到

public class StarvingSingleton {
private static StarvingSingleton starvingSingleton=new StarvingSingleton();
private StarvingSingleton(){
}

public static StarvingSingleton getInstance(){
return starvingSingleton;
}
}

 

  


 

此时我们将原先饿汉模式中的代码优化一下:(将目标对象用枚举进行一层包装

public class EnumStarvingSingleton {
private EnumStarvingSingleton(){}

public static EnumStarvingSingleton getInstance(){
return ContainerHolder.HOLDER.instance;
}

private enum ContainerHolder{
HOLDER;
private EnumStarvingSingleton instance;
ContainerHolder(){
instance = new EnumStarvingSingleton();
}
}

}

 

 


 

这时候我们再用反射来入侵第二层的枚举保护时候,发现无法获取到枚举的构造函数。

 

 

 

此时我们跟进源码,发现枚举类确实是有个带有两个参数的构造方法,

 

 

此时我们再次用反射获取该构造方法进行突破。

 

 

此时报错的信息明确的告诉我们:你不能通过反射的形式来创建枚举的对象。

 

到此我们知道了要想构造出安全的单例,可以用枚举的方式包装保护好目标对象(饿汉模式下)

 

posted @ 2021-02-08 21:52  _kerry  阅读(48)  评论(0编辑  收藏  举报