概述:单例模式是设计模式中最简单的模式之一,它确保每个类只实例化一个对象。常见的写法有:饿汉式、懒汉式、双重校验锁、静态内部类、枚举。
饿汉式:
package com.yzz.hungry;
public class Singleton {
private static Singleton instance = new Singleton(); //classloader装载该类时,初始化静态成员变量
private Singleton() {} //构造函数设为私有,那是肯定的
public static Singleton getInstance() {
return instance;
}
}
这种方式就像它的名字所表达的一样,上来就进行实例化(饿汉上来就是吃= =!)。它在类装载时就进行了实例化,从而避免多线程访问下的创建多个实例的问题。但某些场景下,如实例化这个对象很耗资源,想让它需要时再进行实例化,那么需要延迟加载(lazy loading),下面介绍第二种方式。
懒汉式:
package com.yzz.lazy;
public class Singleton {
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
这种方式不是在类装载时进行实例化。但在多线程情况下,多个线程同时进入了if(instance == null)条件中,则会实例化多个对象。简单的解决方法是用synchronized 修饰getInstance。但是这种方法效率很低,大部分线程都处于不必要的等待状态。下面的双重校验锁则是对它优化。
双重校验锁:
package com.yzz.doublecheck;
public class Singleton {
private static Singleton instance = null;
private Singleton(){}
public static Singleton getInstance() {
if(instance == null) {
synchronized (Singleton.class) {
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
既保证了延迟加载,又解决了多线程同步问题。 注意在JDK1.5之后,双重检查锁定才能够正常达到单例效果,深入了解可以参考网上其他资料。
静态内部类:
package com.yzz.staticinner;
public class Singleton {
private Singleton(){}
private static class SingletonHandler{
private static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingletonHandler.instance;
}
}
这种方式利用了classloader的机制来保证初始化instance时只有一个线程,这种方式是Singleton类被装载了,instance不一定被初始化。因为SingletonHolder类没有被主动使用,只有显示通过调用getInstance方法时,才会显示装载SingletonHolder类,从而实例化instance,从而达到懒加载的效果。
枚举:
package com.yzz.enum;
public enum Singleton {
INSTANCE;
}
《Effective Java》作者所推荐的一种写法,这种方式不仅能防止反序列化重新生成对象,也能解决多线程同步问题。对枚举不熟悉的同学可以参考以下文
章:http://blog.csdn.net/u014082714/article/details/52270462
http://www.importnew.com/6461.html
后续文章介绍反射和反序列化如何破坏单例模式。