单例模式
单例模式就是在系统运行期间有且只有一个实例,且只能提供私有的构造器,保证不能随意创建该类的实例。
第一种(饿汉模式)
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()方法。
小结
- 懒汉:类加载时不创建实例,因此类加载速度快,但运行速度较慢,具备延迟加载的特性,但是又不存在线程安全问题
- 饿汉:类加载时完成初始化,所以类加载慢,但获取对象速度快
- 懒汉是“时间换空间”,饿汉就是“空间换时间”