为什么要使用单例模式? 单例模式是用来保证这个在运行期间只会被创建一个类实例,提供一个全局唯一访问这个类实例的访问点,getInstance方法。单例模式的本质:控制实例数目
一般来说,单例模式的实现方式有五种,分别是
懒汉式饿汉式双重检测锁静态内部类枚举实现单例模式的步骤也比较固定: 1、私有化构造器 2、类的内部创建对象 3、向外部暴露一个静态的公共方法
起到了懒加载的效果,但是只能在单线程的环境下使用,如果是在多线程的环境下,一个线程进入了if(instance==null)的判断语句,还未来得及往下执行,另一个线程也通过了这个判断语句,这时会产生多个实例,所以在多线程环境下不可使用这种方式
优点:写法简单,在类加载时候就完成了实例化,避免了线程同步的问题 缺点:在类加载的时候就实例化了,没有达到懒加载的效果,如果从始至终都没有用到这个类,则会造成内存浪费
1、两次检查,保证线程安全 2、延迟加载,效率较高
1、这种方式采用了类加载在的机制保护了初始化实例时,只有一个线程 2、使用静态内部类的方式在Singleton被加载时并不会实例化,而是调用getInstance的时候才会实例化 3、类的静态属性只会在第一次加载的时候初始化,这里JVM帮助我们保证了线程的安全性 4、此方式线程安全,利用了静态内部类的特性实现了延迟加载,效率高
直接使用Singleton.INSTANCE来获取
有三种方式能够破坏单例,反射,克隆,序列化 可以通过反射机制的newInstance()方法来创建实例,这样就相当于创建了一个新的实例。
如何防止以上三种方式破坏单例呢? 1、防止反射破坏 首先定义一个全局变量开关isFirstCreat默认是开启的 当一次加载时将其状态修改为关闭状态
private Singleton(){ // 防放射破坏代码,如果是通过反射调用就抛出运行时异常 if (!isFirstCreat) { throw new RuntimeException("单例构造器禁止反射调用"); } }2、防止克隆破坏
重写clone()方法 protected Singleton clone() throws CloneNotSupportedException { return singleton; }3、防止序列化破坏
private Object readResolve() { return singleton; }