【设计模式】之单例模式

单例模式(创建型设计模式)

分为 :饿汉式单例模式、懒汉式单例模式、线程安全的懒汉式单例模式;

标准回答 :
  • 含义:一个类仅有一个实例化对象,其最大特点是构造函数私有化;
  • 特点:构造函数私有化,从而避免外界直接使用构造函数直接实例化该类的对象。
  • 单例模式主要分为饿汉式,懒汉式,线程安全的懒汉式。
    • 饿汉式在类加载是就创建了实例对象,但是这样有可能造成资源的浪费;
    • 懒汉式,在类第一次被调用时创建实例,这样可能会造成线程安全问题;
    • 线程安全的懒汉式,则是在懒汉式的基础上加锁
一、单例模式要做的
  • 1、单例类只能有一个实例。
  • 2、单例类必须自己创建自己的唯一实例。(构造函数私有化)
  • 3、单例类必须给所有其他对象提供这一实例。(通过公有的getInstance方法,提供一个全局访问点)
二、单例模式主要解决的问题:

主要解决:一个全局使用的类频繁地创建与销毁。

何时使用:当您想控制实例数目,节省系统资源的时候。

三、单例模式使用场景:
  • 1、要求生产唯一序列号。
  • 2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
  • 3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。

1.饿汉式单例模式: 在类加载时就会初始化静态变量实例,这时候类的私有构造函数就会被调用,创建唯一的实例。
# 是否多线程安全:是;它基于 classloader 机制避免了多线程的同步问题
# 其他描述:
	这种方式比较常用,但容易产生垃圾对象。
- 优点:没有加锁,执行效率会提高。
- 缺点:类加载时就初始化,浪费内存。
public class Singleton{
    //在类加载时就会初始化静态变量实例
	private static Singleton instance = new Singleton(); 
	// 构造方法私有,确保外界不能直接实例化
    private Singleton(){} 
    //通过公有的静态方法获取实例对象
    public static Singleton getInstance(){ 
        return instance; 
    } 
}
2.懒汉式单例模式: 类在加载时不会初始化静态变量instance,而是在第一次被调用时将自己初始化。
# 是否多线程安全:否;因为没有加锁 synchronized
# 其他描述:
	这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程,不要求线程安全,在多线程不能正常工作。
public class Singleton { 
    //先置空,在调用的时候实例化对象
    private static Singleton instance = null; 
    // 私有构造方法,确保外界不能直接实例化。
    private Singleton() {} 
    // 通过公有的静态方法获取对象实例 
    public static Singleton getInstace() {
        if (instance == null) { 
            instance = new Singleton(); } 
        return instance; 
    } 
} 
问题:

如果线程A和B同时调用此方法,会出现执行if (instance == null)语句时都为真的情况,那么线程A和B都会创建一个对象,那内存中就会出现两个对象,这违反了单例模式的定义。

如何解决:线程安全的懒汉式

为解决这一问题,使用synchronized关键字对静态方法 getInstance()进行同步,防止多线程同时进入造成 instance 被多次实例化。

3.线程安全的的懒汉式单例模式
# 是否多线程安全:是;因有加锁 synchronized
# 其他描述:
这种方式具备很好的 lazy loading,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步。
	优点:第一次调用才初始化,避免内存浪费。
	缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
getInstance() 的性能对应用程序不是很关键(该方法使用不太频繁)。
public class Singleton { 
    private static Singleton instance = null; 
    // 私有构造方法,确保外界不能直接实例化。 
    private Singleton() {} 
    // 通过公有的静态方法获取对象实例 
    synchronized public static Singleton getInstace() { 
        if (instance == null) { 
            instance = new Singleton(); 
        } 
        return instance; 
    } 
}
4.饿汉式和懒汉式的对比:
饿汉式单例类在资源利用效率上不如懒汉式单例类,但从速度和反应时间来看,饿汉式单例类要优于懒汉式单例类。

资源利用效率:饿汉式<懒汉式;

速度和反应上:饿汉式>懒汉式;

5.单例模式优缺点:
单例模式的优点:在一个对象需要频繁的销毁、创建;而销毁、创建性能又无法优化时,单例模式的优势尤其明显 ;
  • 在内存里只有一个实例,减少了内存的开销;尤其是频繁的创建和销毁实例
  • 在一个对象的产生需要比较多资源时,如读取配置、产生其他依赖对象时,则可以通过在启用时直接产生一个单例对象,然后用永久驻留内存的方式来解决;
  • 单例模式可以避免对资源的多重占用;因为只有一个实例,避免了对一个共享资源的并发操作;
  • 单例模式可以在系统设置全局的访问点,优化和共享资源访问;
单例模式的缺点:
  • 单例模式没有接口,不能继承;无法创建子类,扩展困难;若要扩展,除了修改代码基本上没有第二种途径可以实现;
  • 单例模式对测试不利;在并行开发环境中,如果采用单例模式的类没有完成,是不能进行测试的;
  • 单例模式与单一职责原则有冲突;一个类应该只实现一个逻辑,而不关心它是否是单例的,是不是要用单例模式取决于环境

你可能感兴趣的:(JAVA---设计模式,单例模式,设计模式,java,spring,boot,分布式)