• 单例模式详解


    目录

        1 单例模式概念

        2 单例模式的演示

               3 使用反射和序列化破解懒汉单例模式 以及如何防漏洞


    概念

        单例模式,就是一个类只有一个实例对象,不管怎么做,都只有这个一个实例对象

        单例模式优点:只生成一个实例,减少了性能开销,当一个对象的生产需要比较多的资源时,如读取配置 产生其他依赖对象时,则可以通过应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。   

        单例模式可以在系统设置全局的访问点,优化环共享资源访问时,例如可以设计一个单类负责所有数据表的映射处理

        常见的五种单例模式的实现方式 主要:1 饿汉模式(线程安全,调用效率高,但是不能延迟加载) 2懒汉模式(线程安全,调用效率不高,可以延时加载)

        其他 1 双重检测锁模式(由于jvm底层模型原因,会出问题,不推荐使用)2 静态内部类式(线程安全,调用效率高,但是,可以延迟加载,顾全了 饿汉模式和懒汉模式的有点,但又没有其缺点)3 枚举单例(线程安全,调用效率高,不能延时加载)


     

    代码示例 一  懒汉模式   (线程安全,调用效率不高,能延迟加载) 

        

    package singleton;
    
    public class SingletonDemo1 {
    	// 将构造方法私有化,防止外部访问,因此不可new出此类的对象
    	private SingletonDemo1() {
    		// TODO Auto-generated constructor stub
    	}
    
    	// 定义静态的本类对象
    	private static SingletonDemo1 sing;
    
    	// 写一个公开方法给外部调用 通过该方法获取实例对象 加上synchronized设为线程安全的
    	public static synchronized SingletonDemo1 getInstance() {
    		// 如果sing==null表明还没有被new new出一个sing返回 否则直接返回sing
    		if (sing == null) {
    			sing = new SingletonDemo1();
    			return sing;
    		} else {
    			return sing;
    		}
    
    	}
    
    }
    

      

    package singleton;
    
    public class SingletonTest {
    	public static void main(String[] args) {
    		SingletonDemo1 d1 = SingletonDemo1.getInstance();
    		SingletonDemo1 d2 = SingletonDemo1.getInstance();
    		SingletonDemo1 d3 = SingletonDemo1.getInstance();
    		System.out.println(d1);
    		System.out.println(d2);
    		System.out.println(d3);
    
    	}
    }
    

      

    对象内存地址一致


     

    代码示例 二 饿汉模式   (线程安全,调用效率高,但是不能延迟加载) 

       

    package singleton;
    
    public class SingletonDemo02 {
    	// 将构造方法私有化,防止外部访问,因此不可new出此类的对象
    	private SingletonDemo02() {
    		// TODO Auto-generated constructor stub
    	}
    	// 定义静态的本类对象 直接new出实例
    	private static final SingletonDemo02 sing = new SingletonDemo02();
    	// 写一个公开方法给外部调用 通过该方法获取实例对象 加上synchronized设为线程安全的
    	public static synchronized SingletonDemo02 getInstance() {
    		return sing;
    	}
    
    }
    

      

    package singleton;
    
    public class SingletonTest {
    	public static void main(String[] args) {
    		SingletonDemo02 d1 = SingletonDemo02.getInstance();
    		SingletonDemo02 d2 = SingletonDemo02.getInstance();
    
    		System.out.println(d1);
    		System.out.println(d2);
    	
    
    	}
    }
    

      

       内存地址一致 


    示例三  内部静态类方式  (线程安全,调用效率高,但是,可以延迟加载,顾全了 饿汉模式和懒汉模式的有点,但又没有其缺点)

      

        

         

    package singleton;
    
    public class SingletonDemo03 {
    	//定义一个静态内部类
    	private static class SingStatic {
    		private static final SingletonDemo03 sing = new SingletonDemo03();
    	}
    	//公开的方法,不需要加synchronized 因为他本身就是线程安全的
    	public static  SingletonDemo03 getInstance() {
    		return SingStatic.sing;
    	}
    }
    

      

    package singleton;
    
    public class SingletonTest {
    	public static void main(String[] args) {
    		SingletonDemo03 d1 = SingletonDemo03.getInstance();
    		SingletonDemo03 d2 = SingletonDemo03.getInstance();
    
    		System.out.println(d1);
    		System.out.println(d2);
    	
    
    	}
    }
    

      


    示例四 枚举式单例模式 (线程安全,调用效率高,不难延时加载)

        

    package singleton;
    
    /**
     * 枚举方式可以避免 反射和反序列化的漏洞,调用效率也比较高,很遗憾没有延迟加载
     * 
     * @author re
     *
     */
    public enum SingletonDemo04 {
    	// 这个枚举元素本身就是单例对象
    	instance;
    	// 可以写自己想要的操作
    	public void printenum() {
    		System.out.println("这是枚举示例");
    	}
    
    }
    

      

    package singleton;
    
    public class SingletonTest {
    	public static void main(String[] args) {
    		SingletonDemo04 d1 = SingletonDemo04.instance;
    		SingletonDemo04 d2 = SingletonDemo04.instance;
    
    		System.out.println(d1 == d2);
    
    	}
    }
    

      

    比较为true  是同一个对象


    破解单例模式 和防漏洞 (枚举无法破解,因为它是基于JVM底层实现的)

       一懒汉模式为例,使用反序列化和反射进行破解   

       1 使用反射破解

    package singleton;
    
    public class SingletonDemo1 {
    	// 将构造方法私有化,防止外部访问,因此不可new出此类的对象
    	private SingletonDemo1() {
    		// TODO Auto-generated constructor stub
    	}
    
    	// 定义静态的本类对象
    	private static SingletonDemo1 sing;
    
    	// 写一个公开方法给外部调用 通过该方法获取实例对象 加上synchronized设为线程安全的
    	public static synchronized SingletonDemo1 getInstance() {
    		// 如果sing==null表明还没有被new new出一个sing返回 否则直接返回sing
    		if (sing == null) {
    			sing = new SingletonDemo1();
    			return sing;
    		} else {
    			return sing;
    		}
    
    	}
    
    }
    

      

    package singleton;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    
    public class SingletonTest {
    	public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException,
    			IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    		// 获取class对象
    		Class clazz = SingletonDemo1.class;
    		// 获取构造器
    		Constructor c1 = clazz.getDeclaredConstructor(null);
    		c1.setAccessible(true);// 跳过访问检查 如果不设为true 则无法访问私有属性,
    		// 因此可以访问私有的构造方法,从而创建对象,利用这个漏洞可以破解单例模式
    		SingletonDemo1 d1 = (SingletonDemo1) c1.newInstance(null);
    		SingletonDemo1 d2 = (SingletonDemo1) c1.newInstance(null);
    		System.out.println(d1);
    		System.out.println(d2);
    	}
    }
    

      

    输出的  对象地址不一样   将SinglentoDemo1中的私有构造方法改为  可防止漏洞,不过我的这个有些问题,加上之后当sing!=null new对象时,并不能抛出异常。

    private SingletonDemo1() {
    		// TODO Auto-generated constructor stub
    		if(sing!=null){
    			//如果有已有sing实例,表示被new过,再创建对象时抛出异常
    			throw new RuntimeException();
    		}
    	}

    反序列化防止漏洞方法

      在单例类中加入  下面这个方法  方法名称和返回值类型不要改动

    // 在反序列化时,直接调用这个方法,返回指定的对象,无需再新建一个对象
    	private Object readResolve() {
    		return sing;
    	}
    

     枚举式单例模式和静态内部类单例模式如何选择

      

  • 相关阅读:
    Mybatis框架学习笔记一(基于注解的配置)
    HDU 1686 Oulipo (KMP模板题)
    监控Windows性能指标
    Locust设置检查点
    《TCP/IP网络编程》读书笔记
    基于单向链表的队列的实现
    windows下基于异步通知IO模型的回声服务器和客户端的实现
    c语言实现迭代器iterator
    c语言hash表的实现
    c语言双向链表的实现
  • 原文地址:https://www.cnblogs.com/sanduweiliangxtx/p/6144712.html
Copyright © 2020-2023  润新知