单例模式(Singleton Pattern)(二)
的写法来完成单例模式。当然volatile或多或少也会影响到性能,最重要的是我们还要考虑JDK1.42以及之前的版本,所以本文中单例模式写法的改进还在继续。
4. 饿汉式实现(Hungry man):
复制代码
/**
* @author YYC
* Hungry man. Using class loader to make it thread-safe
*/
public class SingletonExample2 {
private static SingletonExample2 instance = new SingletonExample2();
private SingletonExample2(){}
public static SingletonExample2 getInstance(){
return instance;
}
}
复制代码
根据Java Language Specification,JVM本身保证一个类在一个ClassLoader中只会被初始化一次。那么根据classloader的这个机制,我们在类装载时就实例化,保证线程安全。
但是,有些时候,这种创建方法并不灵活。例如实例是依赖参数或者配置文件的,在getInstance()前必须调用某些方法设置它的参数。
5. 静态内部类实现(static inner class):
复制代码
/**
* @author HKSCIDYX
* static inner class: make it thread-safe and lazy-loading
*/
public class SingletonExample3 {
private SingletonExample3(){}
public static SingletonExample3 getInstance(){
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder{
final static SingletonExample3 INSTANCE = new SingletonExample3();
}
}
复制代码
利用classloader保证线程安全。这种方法与第四种方法最大的区别是,就算SingletonExample3类被装载了,instance不一定被初始化,因为holder类没有被主动使用。相比而言,这种方法比第四种方法更加合理。
6. 枚举实现(Enum):
《Effective Java, 2nd》第三条:enum是实现Singleton的最佳方法:
复制代码
/**
* @author HKSCIDYX
* Enum
*/
public enum SingletonExample4 {
INSTANCE;
public void whateverMethod(){
}
}
复制代码
这种做法,其实还没真正在项目或者工作中见过。根据《Effective Java, 2nd》第三条,这种实现方法:
1. 简洁
2. JVM可以保证enum类的创建是线程安全(意味着其它方法的线程安全得由程序员自己去保证),
3. JVM可以无偿提供序列化机制。传统的单例模式实现方法都有个问题:一旦实现了serializable接口,他们就不再是单例的了。因为readObject()方法总会返回一个新的实例。因此为了维护并保证单例,必须声明所有实例域都是transient的,且提供一个readRevolve()方法:
复制代码
/**
*
* @author HKSCIDYX
* Handle Serialized situation
*/
public class SingletonExample5 implements Serializable{
private static final long serialVersionUID = 1L;
private static SingletonExample5 INSTANCE = new SingletonExample5();
//if there's other states to maintain, it must be transient
private SingletonExample5(){}
public static SingletonExample5 getInstance(){
return INSTANCE;
}
private Object readResolve(){
return INSTANCE;
}
}