设计模式-单例模式

一、定义

 确保某个类只有一个实例,并向整个系统提供出这个实例。

二、类型

 创建型

三、适用场景

 想确保任何情况下都只有一个实例

四、优点

  • 内存只有一个实例,节省内存。
  • 避免对资源多重占用。
  • 在系统设置全局访问点,优化和共享资源访问。

五、缺点

  •  一般没有接口,扩展困难。
  • 与单一职责有冲突。

六、类图

 过于简单,略

七、代码实现

1、懒汉式:

package com.wms.createtype.singleton;

public class LazySingleton {
    private static LazySingleton lazySingleton = null;
    private LazySingleton() {}
    public static LazySingleton getInstance() {
        synchronized (LazySingleton.class) {
            if (lazySingleton == null) {
                lazySingleton = new LazySingleton();
            }
        }
        return lazySingleton;
    }
}

 2、双重检查式:

package com.wms.createtype.singleton;

public class DoubleCheckSingleton {
    // volatile 禁止指令重排
    private volatile static DoubleCheckSingleton doubleCheckSingleton = null;
    private DoubleCheckSingleton() {}
    public static DoubleCheckSingleton getInstance() {
        if (doubleCheckSingleton == null) {
            synchronized (DoubleCheckSingleton.class) {
                if (doubleCheckSingleton == null) {
                    // 1、分配内存给对象
                    // 2、初始化对象
                    // 3、赋值给doubleCheckSingleton
                    // jvm的指令重排可能会使得2和3这两步顺序不确定
                    // 当执行顺序是1->3->2的时候,就会出现问题,此时doubleCheckSingleton不为空,别的线程来获取这个单例对象
                    // 时就可能拿到还没初始化的这个对象,此时如果别的线程直接使用,就会出错。因此加上volatile禁止jvm指令重排
                    doubleCheckSingleton = new DoubleCheckSingleton();
                }
            }
        }
        return doubleCheckSingleton;
    }
}

 3、饿汉式:

package com.wms.createtype.singleton;

public class HungarySingleton {
    private static HungarySingleton hungarySingleton = new HungarySingleton();
    private HungarySingleton() {}
    public static HungarySingleton getInstance() {
        return hungarySingleton;
    }
}

4、静态内部内:

package com.wms.createtype.singleton;

public class StaticInnerClassSingleton {
    private StaticInnerClassSingleton() {}

    public static StaticInnerClassSingleton getInstance() {
        return InnerClass.staticInnerClassSingleton;
    }
    private static class InnerClass {
        private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
    }
}

5、枚举单例

package com.wms.createtype.singleton;

public enum EnumSingleton {
    INSTANCE;
    
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

 八、破坏单例

1、反序列化破坏单例

测试函数:

package com.wms.createtype.singleton;

import java.io.*;

public class TestDesignParttern {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        HungarySingleton hungarySingleton = HungarySingleton.getInstance();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("singletion"));
        objectOutputStream.writeObject(hungarySingleton);
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("singletion"));
        HungarySingleton hungarySingleton01 = (HungarySingleton) objectInputStream.readObject();
        
        System.out.println(hungarySingleton == hungarySingleton01);  // false
    }
}

修改单例类:

package com.wms.createtype.singleton;

import java.io.Serializable;

public class HungarySingleton implements Serializable {
    private static HungarySingleton hungarySingleton = new HungarySingleton();
    private HungarySingleton() {}
    public static HungarySingleton getInstance() {
        return hungarySingleton;
    }

    // 加上该方法在反序列化的时候返回已存在的单例对象
    public Object readResolve() {
        return hungarySingleton;
    }
}

 防御方式:单例模式中增加反序列化方法,该方法隐式调用。

2、反射破坏单例

网上有些通过构造方法防御:

package com.wms.createtype.singleton;

import java.io.Serializable;

public class HungarySingleton implements Serializable {
    private static HungarySingleton hungarySingleton = new HungarySingleton();
    private HungarySingleton() {
        if (hungarySingleton != null) {
            throw new RuntimeException("单例模式不允许调用构造方法实例化");
        }
    }
    public static HungarySingleton getInstance() {
        return hungarySingleton;
    }

    // 加上该方法在反序列化的时候返回已存在的单例对象
    public Object readResolve() {
        return hungarySingleton;
    }
}

破坏方式:

package com.wms.createtype.singleton;

import java.io.Serializable;

public class HungarySingleton implements Serializable {
    private static final HungarySingleton hungarySingleton = new HungarySingleton();
    private HungarySingleton() {
        if (hungarySingleton != null) {
            throw new RuntimeException("单例模式不允许调用构造方法实例化");
        }
    }
    public static HungarySingleton getInstance() {
        return hungarySingleton;
    }

    // 加上该方法在反序列化的时候返回已存在的单例对象
    public Object readResolve() {
        return hungarySingleton;
    }
}
public class StaticInnerClassSingleton {
    private StaticInnerClassSingleton() {
        if (InnerClass.staticInnerClassSingleton != null) {
            throw new RuntimeException("单例模式不允许调用构造方法实例化");
        }
    }

    public static StaticInnerClassSingleton getInstance() {
        return InnerClass.staticInnerClassSingleton;
    }
    private static class InnerClass {
        private static final StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
    }
}

防御方式:饿汉式和静态内部类,增加final修饰,可防止反射攻击,其他都无法防御。

3、防御任何破坏单例的方式:Effective Java推荐尽可能地使用枚举来实现单例

posted @ 2018-12-31 22:34  请叫我大表哥  阅读(211)  评论(0编辑  收藏  举报