为什么要用单例,你真的会写单例模式吗
优秀的设计结构可以规避很多潜在的性能问题,对系统性能的影响可能远远大于代码的优化,所以我们需要知道一些设计模式和方法。
单例模式:
单例模式是一种对象创建模式,用于生产一个对象的实例,它可以确保系统中一个类只产生一个实例,这样做有两个好处:
1.对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销。
2.由于new操作的次数减少,所以系统内存的使用评率也会降低,这将减少GC压力,缩短GC停顿时间。
由于以上两点可知单例模式的使用对于系统的关键组件和频繁使用的对象来说是可以有效的改善系统的性能的。
单例的核心是通过一个方法返回唯一的一个对象实例,首先单例类必须有一个private访问级别的构造函数,因为,只有这样,才能保证单例不会再系统中的其他代码内被实例化,其次,instance成员变量和getInstance方法必须是static的。
需要对instance实例做延迟加载
假如单例的创建过程很慢(构造方法中有其他耗时操作),并且不是延迟加载的(由于instance成员变量是static定义的,因此在JVM加载单例类时,单例对象就会被创建),如果此时这个单例类还在系统中扮演着其他角色(单例类还有其他非创建单例的静态方法),那么在任何使用这个单例类的地方都会初始化这个单例变量,而不管是否会被用到。也就是说虽然并没有使用单例类,但是它还是被创建出来了,这是我们不愿意看到的,为了解决这个问题,就需要引入延迟加载机制。
对于静态变量instance初始值赋null,确保系统启动时没有额外的负载,在getInstance()工厂方法中,判断当前单例是否已存在,若存在则返回,若不存在则创建单例,同时getInstance()方法应该是同步的。
为了延迟加载而引入同步关键字会降低系统性能,为了解决这个问题,可以使用内部类来维护单例的实例,当单例类被加载时,其内部类并不会被初始化,所以可以确保单例类被加载进入JVM时,不会初始化单例类,而当getInstance方法被调用时才会加载SingletonHolder从而初始化instance,由于实例的建立是在类加载时完成,故天生对多线程友好,getInstance方法也不需要使用同步关键字,所以这种方法兼容上边说的两种实现的优点。
通常情况下,以上方式实现的单例已经可以确保在系统中中存在唯一的实例了,但是也有例外的情况导致系统生成多个实例,比如,在代码中通过反射机制强行调用单例类的私有构造函数来生成多个单例。针对这种极端的情况也有克服的办法,具体办法请参考笔者头条号中讲解单例模式的其他两篇文章。