设计模式之单例模式

132 阅读3分钟

「这是我参与2022首次更文挑战的第18天,活动详情查看:2022首次更文挑战」。

什么是单例模式

单例模式是一种常用的软件设计模式,其定义是单例对象的类只能允许一个实例存在。

许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。

单例的实现

  1. 将该类的构造方法定义为私有方法,这样其他处的代码就无法通过调用该类的构造方法来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例;
  2. 在该类内提供一个静态方法,当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用。

饿汉模式

使用类的时候已经将对象创建完毕,不管以后会不会使用到该实例化对象,先创建了再说

public class Singleton {
​
    // 将自身实例化对象设置为一个属性,并用static、final修饰
    private static final Singleton instance = new Singleton();
    
    // 构造方法私有化
    private Singleton() {}
    
    // 静态方法返回该实例
    public static Singleton getInstance() {
        return instance;
    }
}

优点:实现起来简单,没有多线程同步问题。

缺点:当类SingletonTest被加载的时候,会初始化static的instance,静态变量被创建并分配内存空间,从这以后,这个static的instance对象便一直占着这段内存(即便你还没有用到这个实例),当类被卸载时,静态变量被摧毁,并释放所占有的内存,因此在某些特定条件下会耗费内存。

懒汉模式

调用get()方法时实例才被创建,先不急着实例化出对象,等要用的时候才给你创建出来

public class Singleton {
​
    // 将自身实例化对象设置为一个属性,并用static修饰
    private static Singleton instance;
    
    // 构造方法私有化
    private Singleton() {}
    
    // 静态方法返回该实例
    public static Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
​

优点:实现起来比较简单,当类SingletonTest被加载的时候,静态变量static的instance未被创建并分配内存空间,当getInstance方法第一次被调用时,初始化instance变量,并分配内存,因此在某些特定条件下会节约了内存。

缺点:在多线程环境中,这种实现方法是完全错误的,根本不能保证单例的状态。

双重加锁机制

public class Singleton
    {
        private static Singleton instance;
        //程序运行时创建一个静态只读的进程辅助对象
        private static readonly object syncRoot = new object();
        private Singleton() { }
        public static Singleton GetInstance()
        {
            //先判断是否存在,不存在再加锁处理
            if (instance == null)
            {
                //在同一个时刻加了锁的那部分程序只有一个线程可以进入
                lock (syncRoot)
                {
                    if (instance == null)
                    {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }

单例模式的最佳实现方式。内存占用率高,效率高,线程安全,多线程操作原子性。

总结

当然,单例模式的实现方法还有很多。但是,这几种是比较经典的实现,也是我们应该掌握的几种实现方式。

从实现中,我们可以总结出,要想实现效率高的线程安全的单例,我们必须注意以下两点:

  • 尽量减少同步块的作用域;
  • 尽量使用细粒度的锁。