创建型模式——单例模式

单例模式


一、介绍

  • 单例模式是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点

二、单例模式实现

  • 实现方式
    • 将默认构造函数设为私有, 防止其他对象使用单例类的 new运算符。
    • 新建一个静态构建方法作为构造函数。 该函数会 “偷偷” 调用私有构造函数来创建对象, 并将其保存在一个静态成员变量中。 此后所有对于该函数的调用都将返回这一缓存对象。

2.1 饿汉式

  • 使用私有的静态常量在内部创建

  • 示例代码

    public class Singleton {
        //1.本类内部创建对象实例,也可以使用静态代码块创建
    	private final static Singleton instance = new Singleton();
    
        
    	//2. 构造器私有化,  外部不能能 new 
        private Singleton() {
        }
        //3. 提供一个公有的静态方法,返回实例对象
        public static Singleton getInstance() { 
            return instance;
        }
    }
    
    
  • 优缺点

    • 优点:写法简单,在类加载时就进行了初始化。避免了线程同步的问题
    • 缺点:在类加在时就进行了初始化,若这个类从头到尾都没有使用过,会造成内存浪费
  • 结论:该方式可以使用,但是有可能会造成内存浪费

2.2 懒汉式(线程不安全)

  • 在第一次获取对象的时候创建

  • 示例代码

    public class Singleton {
        //1.本类内部创建对象实例
    	private final static Singleton instance;
    
        
    	//2. 构造器私有化,  外部不能能 new 
        private Singleton() {
        }
        //3. 提供一个公有的静态方法,返回实例对象
        public static Singleton getInstance() { 
            if(instance == null){
                instance = new Singleton();
            }
            return instance;
        }
    }
    
    
  • 优缺点

    • 优点:起到了懒加载的效果,不存在浪费内存
    • 缺点:只能在单线程中使用。若在多线程中使用可能会产生多个实例:(线程一进入if方法但是还没执行创建实例时,线程二也在创建实例,这种情况就会产生两个实例)
  • 结论:在开发中别用这种方法

2.3 懒汉式(线程安全,同步)

  • 在第一次获取对象的时候创建(获取实例对象的方法改成同步的)

  • 示例代码

    public class Singleton {
        //1.本类内部创建对象实例
    	private final static Singleton instance;
    
        
    	//2. 构造器私有化,  外部不能能 new 
        private Singleton() {
        }
        //3. 提供一个公有的静态同步方法,返回实例对象
        public static synchronized Singleton getInstance() { 
            if(instance == null){
                instance = new Singleton();
            }
            return instance;
        }
    }
    
    
  • 优缺点

    • 优点:起到了懒加载的效果,不存在浪费内存,没有线程安全问题
    • 缺点:效率太低,每次获取对象都被加锁
  • 结论:在开发中别用这种方法

2.4 双重检查

  • 在第一次获取对象的时候创建

  • 示例代码

    public class Singleton {
        //1.本类内部创建对象实例
    	private final static Singleton instance;
    
        
    	//2. 构造器私有化,  外部不能能 new 
        private Singleton() {
        }
        //3. 提供一个公有的静态方法,返回实例对象
        public static Singleton getInstance() { 
            if(instance == null){
                synchronized (Singleton.class){
                    if(instance == null){
                		instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }
    
    
  • 优缺点

    • 优点:起到了懒加载的效果,不存在浪费内存,没有线程安全问题,没有性能问题
  • 结论:在开发中推荐使用这种方法

2.5 静态内部类

  • 在第一次获取对象的时候创建

  • 示例代码

    public class Singleton {
        //1.本类内部创建对象实例 volatile:禁止重排序
    	private static volatile Singleton instance;
    
        
    	//2. 构造器私有化,  外部不能能 new 
        private Singleton() {
        }
        //写一个静态内部类,该类中有一个静态属性 Singleton 
        private static class SingletonInstance {
        	private static final Singleton INSTANCE = new Singleton();
        }
    
        //提供一个静态的公有方法,直接返回 SingletonInstance.INSTANCE 
        public static synchronized Singleton getInstance() {
    
        	return SingletonInstance.INSTANCE;
        }
    
    }
    
    
  • 优缺点

    • 优点:起到了懒加载的效果,不存在浪费内存,没有线程安全问题,没有性能问题。
  • 结论:这种方式采用了类装载的机制来保证初始化实例时只有一个线程。在开发中推荐使用这种方法

2.6 枚举

  • 在第一次获取对象的时候创建

  • 示例代码

    public enum Singleton {
        INSTANCE;
    
    	public void sayOK() { 
            System.out.println("ok~");
    	}
    
    }
    
    
  • 优缺点

    • 优点:起到了懒加载的效果,不存在浪费内存,没有线程安全问题,没有性能问题,避免反序列化重新创建新的对象
  • 结论:在开发中推荐使用这种方法

三、在Spring中的应用

  • 依赖注入中使用单例模式。DefaultSingletonBeanRegistry

    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                synchronized(this.singletonObjects) {
                    singletonObject = this.singletonObjects.get(beanName);
                    if (singletonObject == null) {
                        singletonObject = this.earlySingletonObjects.get(beanName);
                        if (singletonObject == null) {
                            ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                            if (singletonFactory != null) {
                                singletonObject = singletonFactory.getObject();
                                this.earlySingletonObjects.put(beanName, singletonObject);
                                this.singletonFactories.remove(beanName);
                            }
                        }
                    }
                }
            }
        }
    
        return singletonObject;
    }
    
  • 该方法使用的是,双重检查


总结

  • 单例模式保证了 系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能
  • 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用 new
  • 单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源session 工厂等)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值