Singleton Pattern(单例模式)

1、简介

  单例模式,顾名思义,即在整个系统中,类的实例对象只有一个。

  单例模式具有以下特点:

    • 单例类只能有一个实例
    • 单例类必须自己创建自己的唯一实例
    • 单例类必须给所有其他对象提供这一实例

2、实现

  其实现原理为将构造函数设为private,以让外部无法使用new来实例化对象。单例类内部保存着一个该类的静态实例对象并对外提供。

  2.1 饿汉式

     饿汉式,所谓的“饿”是指一开始就要“吃”,即单例类一被加载就初始化。实现代码如下:

public class Singleton1 {
    private static final Singleton1 instance = new Singleton1();

    private Singleton1() {}
    
    public static Singleton1 getSingleton() {
        return instance;
    }
}

  2.2 懒汉式

  懒汉式,同饿汉式相反,所谓的“懒”指单例类被加载时未被初始化,等到被第一次获取单例对象时才对对象进行初始化。实现了懒加载。实现代码如下:

public class Singleton2 {
    private static Singleton2 instance;

    private Singleton2() {}

    public static Singleton2 getSingleton() {
        if (instance == null)
            instance = new Singleton2();
        return instance;
    }
}

  这种写法是线程不安全的(线程1运行到if之后阻塞,线程2对instance初始化完成,线程1将再次对instance进行初始化),在多线程环境下将不能正常工作。对其getSingleton()方法加锁以解决线程不安全问题,如下:

public class Singleton3 {
    private static Singleton3 instance;
    
    private Singleton3() {}
    
    public synchronized static Singleton3 getSingleton() {
        if (instance == null) 
            instance = new Singleton3();
        return instance;
    }
}

  以上写法属于线程安全型,但是它效率并不高。在instance被初始化之后,使用getSingleton获取对象,该方法仍然是加锁的,导致效率低下。对其进行修改,当instance为null的时候才对方法内部代码进行加锁。不为null时直接返回instance。如下:

public class Singleton4 {
    private static Singleton4 instance;
    
    private Singleton4() {}
    
    public static Singleton4 getSingleton() {
        if (instance == null)
            synchronized(Singleton4.class){
                if (instance == null)
                    instance = new Singleton4();
            }
        return instance;
    }
}

  2.3 静态内部类

public class Singleton5 {
    private static class InstanceClass {
        private static Singleton5 instance = new Singleton5();
    }
    
    private Singleton5() {}
    
    public static Singleton5 getSingleton() {
        return InstanceClass.instance;
    }
}

3、使用场景

  在一个系统中,要求一个类有且只有一个对象时可采用单例模式。例如

  • Java的Runtime对象
  • 要求生成唯一序列号的环境

4、优点

  • 类只有一个实例,从而减小对内存的开销。特别是一个对象需要频繁地创建和销毁时。
  • 由于单例模式只生成一个实例,所以减少了系统的性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后用永久驻留内存的方式来解决。
  • 避免了对资源的多重利用。例如写文件,因为只有一个对象,从而避免了对同一个资源文件的同时写操作。
  • 可以在系统设置全局的访问点,优化和共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理。

5、缺点

  • 单例模式一般没有接口,扩展很困难。
  • 对测试是不利的。在并行开发环境中,如果单例模式没有完成,是不能进行测试的,没有借口也不能使用mock的方式虚拟一个对象。
  • 单例模式与单一职责有冲突。一个类应该只实现一个逻辑,而不关心他是否是单例的,是不是单例取决于环境,单例模式把“要单例”和业务逻辑融合在一个类中。
原文地址:https://www.cnblogs.com/loading4/p/5654591.html