设计模式-单例模式
简述
单例应该是最简单也是最常用的模式了。单例模式通常用在当一个系统只需要唯一一个类,比如线程池,日志打印等。单例模式的类就只有一个,听起来很简单,但是要写好单例却不容易。不信你自己先想想怎么保证系统里面只有一个单例?
单例模式:确保一个类只有一个实例,并且提供一个全局访问点
单例实践
要保证单例的第一步就是要保证类不能随意实例话,new 一个对象的代价是很简单的比如:new Object()。但如果不能new了?没错,我们第一步就是让构造方法私有话,不会对外开放private ObjectConstractor();但是如果我们还是需要使用这个类怎么办了?一个最简单的单例模式就可以写出来了:
1 | public class Singleton { |
其实你可以想到,如果在多线程的环境下,我们上面的代码还是会有问题的,就是线程A和线程B同时同刻读取instance,然后两者都是读到null,然后就AB都会去实例话一次instance,这跟我们预想的不一致。
嗯我们可以做点改进,那就是同步:
1 | public static synchronized Singleton getInstance2(){ |
没错在上列中我们是可以解决掉多线程的情况下,instance实例话两次的情况的,这种方式我们也叫做懒汉式单例模式。但是我们引入了synchronized,这又会造成一个新的问题,那就是我们,我们知道这种同步是会降低性能的,当然如果你的机器配置够好,那么对此就可以完全忽略,但是作为程序员,总有一种想要压榨性能的天生渴望~
让我们再来做些改进:
1 |
|
这种改进的方式是在jvm加载该类的时候就已经初始话了,JVM保证任何线程访问这个类之前一定先创建了该类,这种方式也被形象的称为饿汉式单例模式。
单例模式实现方法
懒汉式单例模式:
1 | package single; |
饿汉式单例模式:
1 | public class Singleton { |
双重加锁校验:
1 | package single.doubblechecking; |
静态内部类:
1 | public class Singleton { |
枚举单例模式:
1 | package single.enums; |
枚举的方式特别有意思,所以我额外还写了一个测试类:
1 | package single; |
这四次输出都是一样的:
1 | java.lang.Object@7f31245a |
用枚举实现单例是<synchronized,历史的原因就不追述了,但是自己写的代码一定要好好的检查。
什么是好的代码?可能就是编写以后不需要再重构的代码。因为它的性能已经是最完美了,顶多也就是加一些判断逻辑而已。