众所周知,单例模式是日常工作中经常会用到的一种设计模式,话不多说,让我们先来看看它的一般写法是怎样的:
在不考虑多线程处理的情况下,这样的写法是没有问题的,但是将这段代码放到多线程的环境中去执行,可能会出现同时存在多个simpleSingleton变量的情况。那么要怎样才能满足在复杂的多线程环境中还能实现单例呢?请看第一种写法:
哈哈,没错,就是在getInstance()方法上加上synchronized关键字,synchronized的作用不必多说,就是给这个方法加锁,保证在多线程环境下每次只会有一个线程执行该方法。但是由于每次调用该方法时,都会进行线程同步,如果在一个调用频繁的环境下,会影响到程序的执行效率。好烦啊,还是有问题,怎么办?!!让我们换个角度想想,既然多次调用该方法会影响效率,为何不在程序编译期就给它来一个静态初始化呢?好办法,这就是我们要介绍的第二种写法:
这样写的话,在静态初始化的时候ourInstance就已经创建了。但是,问题又来了,如果我们在程序中不是经常会用到这个单例,那这样写的话,ourInstance总是会占用一部分内存,造成了资源的浪费!!芽儿哟,难道就没有一种方法,能够在我们需要单例的时候再创建它,而且不会因为频繁同步影响执行效率吗?您好,有的!!让我们回到梦开始的地方,再仔细回想一下,我们在使用单例时,是不是只有第一次执行getInstance()方法的时候才会new一个Singleton实例?那我们是不是可以只在第一次创建Singleton实例时才进行同步?OK,话不多说,来看第三种写法:
我们用双重检查加锁的方式,首先检查实例是否已经被创建,如果尚未创建,“才”进行同步,这样一来只有第一次会同步,这正是我们想要的。volatile关键字确保当singleton被初始化成Singleton实例时,多线程能够正确处理singleton变量。如果性能是你的关注重点的话,那么这个做法可以大大减少getInstance()的时间耗费。
单例模式的三种形态就介绍完了,我们可以根据实际情况来酌情考虑具体使用哪一种。