关于单例设计模式
通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。
Java实现
package com.csdhsm.singleton; /** * @Title: Singleton1.java * @Package: com.csdhsm.singleton * @Description Singleton1 * @author Han * @date 2016-4-12 上午9:26:15 * @version V1.0 */ public class Singleton1 { /** * Description set the constructor to private */ private Singleton1() {} /** @Fields singleton1: */ private Singleton1 singleton1; /** * @Description get the singleton1`s instance * @author Han * @return */ public Singleton1 getInstance(){ if(singleton1 == null){ singleton1 = new Singleton1(); } return singleton1; } }
这是第一种实现方法,大体的思路就是一种懒汉单例(使用时才实例化),粗略的看是去没有什么问题,但是仅仅是在单线程时,如果出现多线程,两个线程同时去获取实例,因为不是原子操作,所以两个线程都会判断实例为null,所以会各实例化一个对象,与单例设计思想不符。
package com.csdhsm.singleton; /** * @Title: Singleton2.java * @Package: com.csdhsm.singleton * @Description Singleton2 * @author Han * @date 2016-4-12 上午9:30:24 * @version V1.0 */ public class Singleton2 { /** * Description set the constructor to private */ private Singleton2(){} /** @Fields singleton2: Singleton2*/ private Singleton2 singleton2; /** * @Description get the singleton2`s instance * @author Han * @return */ public Singleton2 getInstance(){ //add synchronized to avoid creating the instance simultaneously synchronized(this){ if(singleton2 == null){ singleton2 = new Singleton2(); } } return singleton2; } }
这是第二种实现方法,较上一个实现方法,加上了同步块synchronized,这样就避免了多线程同时创建的尴尬情况,代码实现上是没有太大的问题,但是又会出现一个问题,同步块synchronized是一个相当耗时的操作,每次都会进行同步阻塞等待,消耗大量的时间。
package com.csdhsm.singleton; /** * @Title: Singleton3.java * @Package: com.csdhsm.singleton * @Description Singleton3 * @author Han * @date 2016-4-12 上午9:35:26 * @version V1.0 */ public class Singleton3 { /** * Description set the constructor to private */ private Singleton3(){}; /** @Fields singleton3: Singleton3*/ private Singleton3 singleton3; /** * @Description get the singleton3`s instance * @author Han * @return */ public Singleton3 getInstance(){ //if 1 if(singleton3 == null){ synchronized(this){ //if2 if(singleton3 == null){ singleton3 = new Singleton3(); } } } return singleton3; } }
这是第三种实现方法,是上个方法的升级版,加入两个if去判断对象是否已经被实例化,好处就是,在对象还未实例化的时候,会进入第一个if语句内部,而且只会有一个线程可以进入第二个if语句内部去实例化对象,当对象实例化结束之后,以后通过该方法去获取对象时,第一个if语句就已经进不去了,所以也不存在同步阻塞了。但是代码逻辑判断有点多,能不能更简单一点呢??
package com.csdhsm.singleton; /** * @Title: Singleton4.java * @Package: com.csdhsm.singleton * @Description singleton4 * @author Han * @date 2016-4-12 上午9:43:26 * @version V1.0 */ public class Singleton4 { private Singleton4(){}; /** @Fields singleton4: instance in there*/ private static Singleton4 singleton4 = new Singleton4(); /** * @Description get the singleton4`s instance * @author Han * @return */ public Singleton4 getInstance(){ return singleton4; } }
这是第四种实现方法,不同于上面三种方法,这种实现方法叫做饿汉单例,指全局的单例实例在类装载时构建, 急切初始化。这种方法不会存在线程安全,但是,当类中有另外一个static方法被访问,将会引起jvm去初始化instance,最明显的缺点就是如果构造器内的方法比较耗时,则加载过程会比较长。
package com.csdhsm.singleton; /** * @Title: Singleton5.java * @Package: com.csdhsm.singleton * @Description singleton5 * @author Han * @date 2016-4-12 上午9:42:55 * @version V1.0 */ public class Singleton5 { private static class SingletonHolder{ static Singleton5 singleton5 = new Singleton5(); } private Singleton5(){}; public Singleton5 getInstance(){ return SingletonHolder.singleton5; } }
这是第五种实现方法,大概的思路就是引入一个中间容器,当调用Singleton5中的其他static方法的时候,instance不会急着实例化,而是等使用的时候,如果SingletonHolder类没有被加载,就会去加载,起到延迟加载的作用,所以这种方法是懒汉单例,而且没有使用到synchronized同步块。
总结
如果是比较简单的单例类设计,对于一般的应用,构造方法内的代码不涉及到读取配置、远程调用、初始化IOC容器等长时间执行的情况,则可以使用第四种加载方法。相反,则需要使用第五种实例方法,当使用的时候才去实例化,延缓加载。