单例模式
单例模式就是在系统运行期间有且只有一个实例,且只能提供私有的构造器,保证不能随意创建该类的实例。
第一种(饿汉模式)
package cn.smbms.test;public class Singleton {//定义私有访问方法private Singleton() {}//获取实例private static Singleton singleton = new Singleton();//提供一个供外界访问该class的方法public static Singleton getInstance() {return singleton;} }
上述代码在类加载时就完成了初始化操作,故加载类较慢,但是获取对象的速度很快,也称饿汉模式,并且饿汉模式是在类初始化时就以及自行
实例化,因此不存在线程安全问题。
第二种(懒汉模式)
package cn.smbms.test;public class Singleton {//定义私有访问方法private Singleton() {}//获取实例private static Singleton singleton;//提供一个供外界访问该class的方法public synchronized static Singleton getInstance() {if(singleton==null) {singleton= new Singleton();}return singleton;} }
上面第二中形式是lazy initialization, 也就是说第一次调用时初始Singleton,以后就不用再生成了。注意到lazy initialization 形式
中的synchronized,这个synchronized很重要, 如果没有synchronized,那么使用getInstance ()是有可能得到多个Singleton ,这种在
类加载时不创建实例,采用延迟加载的方式,在运行调用时创建实例,也称懒汉模式,即在调用方式时才获取实例。
但在实际开发中,会遇到以下应用场景:
实例化单例类很消耗资源,我们希望可以要吃加载,即不想让它在类加载时就实例化,那如何处理呢?如下
package cn.smbms.test;public class Singleton {//定义私有访问方法private Singleton() {}//获取实例private static Singleton singleton;public static class SingletionHelper{private static Singleton INSTANCE=new Singleton();} public static Singleton getInstance() {singleton= SingletionHelper.INSTANCE;return singleton;}public static Singleton test() {return singleton;} }
上述中,同样利用了classloder的机制来保证初始化instance只有一个线程,但是跟之前的方式略有不同。按照之前的方式只要singleton类被装载了
,那么singleton就会被实例化,并没有达到lazy loading的效果。而现在这种静态内部的方式时:singleton被装载了,却不一定被初始化原因在于没有主
动调用getInstance()方法。
小结
- 懒汉:类加载时不创建实例,因此类加载速度快,但运行速度较慢,具备延迟加载的特性,但是又不存在线程安全问题
- 饿汉:类加载时完成初始化,所以类加载慢,但获取对象速度快
- 懒汉是“时间换空间”,饿汉就是“空间换时间”