【设计模式】常见五种单例模式详解以及操作

五种单例模式

  • 饿汉式
  • 懒汉式
  • 双重检测锁
  • 静态内部类
  • 枚举
  • 使用反射和序列化破解单例模式
  • 解决反射和序列化漏洞
1、饿汉式

描述:加载类时直接创建对象
特点:线程安全、效率高,不可延时加载
代码实现:

public class SingletonDemo {
    /**
     * 类初始化时立即加载
     * 加载类时创建类  线程安全、没有同步(synchronized)调用的效率高
     */
    private  static SingletonDemo singleton = new SingletonDemo();

    /**
     * 私有化构造器
     */
    private SingletonDemo(){
    }

    /**
     * 创建公有获取类
     * @return
     */
    public static SingletonDemo getSingletonDemo(){
        return singleton;
    }
}

2、懒汉式

描述:加载类时不创建对象,在调用时创建
特点:线程安全、效率低,可延时加载
代码实现:

public class SingletonDemo2  {

    /**
     * 创建类对象 不初始化这个对象(延时加载,真正用时再创建)
     */
    private static SingletonDemo2 singletonDemo;

    /**
     * 私有化构造器
     */
    private SingletonDemo2()  {
    }

    /**
     * 公有获取类,使用同步(synchronized) 保证线程安全
     * 因为使用synchronized 所以线程安全 但是效率较低
     * @return
     */
    public static synchronized SingletonDemo2 getSingleton(){
        if(singletonDemo == null){
            singletonDemo = new SingletonDemo2();
        }
        return singletonDemo;
    }
}

3、双重检测锁

描述:在方法中使用synchronized使用
特点:线程安全、效率高,可延时加载;由于编译器优化以及jvm底层内部模型不建议使用
代码实现:

public class SingletonDemo3 {
    /**
     * 创建对象
     */
    private static SingletonDemo3 singleton = null;
    /**
     * 私有化构造器
     */
    private SingletonDemo3() {}
    /**
     * 创建公有获取类
     *
     * @return
     */
    public static SingletonDemo3 getSingletonDemo() {
        if (singleton == null) {
            SingletonDemo3 singletonDemo3;
            synchronized (SingletonDemo3.class) {
                singletonDemo3 = singleton;
                if(singletonDemo3 == null ){
                    synchronized (SingletonDemo3.class){
                        if (singletonDemo3 == null) {
                            singletonDemo3 = new SingletonDemo3();
                        }
                    }
                    singleton = singletonDemo3;
                }
            }
        }
        return singleton;
    }
}
4、静态内部类

描述:在类中使用静态内部类
特点:线程安全、效率高;可延时加载
代码实现:

public class SingletonDemo4 {
    /**
     * 静态内部类
     */
    private static class SingletonDemo4Instance{
        private static final SingletonDemo4 singletonDemo4 = new SingletonDemo4();
    }

    private SingletonDemo4(){

    }
    public static SingletonDemo4 getInstance(){
        return SingletonDemo4Instance.singletonDemo4;
    }
}
5、枚举

描述:天然的单例模式
特点:线程安全,不可延时加载;天然避免反射和序列化的漏洞
代码实现:

public enum SingletonDemo5 {
    //这个枚举元素本身就是一个单例
    // 避免反射 反序列化的漏洞,但是没有延时加载
    INSTANCE;

    /**添加自己需要的方式*/
    public void singletonDemo5(){

    }

}
使用反射破解单例模式

代码实现:

public class Client2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
        SingletonDemo2 singleton = SingletonDemo2.getSingleton();
        SingletonDemo2 singleton1 = SingletonDemo2.getSingleton();
        System.out.println(singleton);
        System.out.println(singleton1);

        //通过反射的方式直接调用私有构造器
        Class<SingletonDemo2> aClass =(Class<SingletonDemo2>) Class.forName("com.singleton.SingletonDemo2");
        Constructor<SingletonDemo2> declaredConstructor = aClass.getDeclaredConstructor(null);
        declaredConstructor.setAccessible(true);
        SingletonDemo2 singletonDemo2 = declaredConstructor.newInstance();
        SingletonDemo2 singletonDemo3 = declaredConstructor.newInstance();
        System.out.println(singletonDemo2);
        System.out.println(singletonDemo3);
    }
 }
使用序列化破解单例

注意:序列化需要被序列化的类实现 Serializable接口

public class Client2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
        SingletonDemo2 singleton = SingletonDemo2.getSingleton();
        SingletonDemo2 singleton1 = SingletonDemo2.getSingleton();
        System.out.println(singleton);
        System.out.println(singleton1);

        //通过反序列化的方式构造多个对象
        FileOutputStream fos = new FileOutputStream("d:/aaaa.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(singleton);
        oos.close();
        fos.close();

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/aaaa.txt"));
        SingletonDemo2 o = (SingletonDemo2)ois.readObject();
        System.out.println(o);

    }
}
修复反射破解单例模式漏洞

在私有构造器的时候,加一层判断,如果不为空就直接抛出异常

 /**
     * 私有化构造器
     */
    private SingletonDemo2()  {
       if(singletonDemo != null){
           throw new RuntimeException();
       }
    }
修复反序列化破解单例模式漏洞

在被序列化的类中,写入 ReadResolve 当序列化时,返回当前类中已有的对象

 /**反序列化时,如果定义了ReadResolve 则直接返回之前的对象*/
    private Object readResolve()throws ObjectStreamException {
        return singletonDemo;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓦然回首的风度

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值