确保某一个类只有一个实例,二期自行实例化并向整个系统提供这个实例。
public class CEO{
private static final CEO mCeo = new CEO();
private CEO(){}
public static CEO getCeo(){
return mCeo;
}
public void doSomething(){}
}
public class Singleton{
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
缺点:即使instance已经被初始化,每次调用getInstance方法都会进行同步,这样会消耗不必要的资源。
public class Singleton{
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
缺点:instance = new Singleton();语句并不是一个原子操作,大致做了3件事情:
由于Java编译器底层优化,执行完1,2和3的顺序时无法保证的。如果3执行完,2未执行前,被切换到B上,这时候instance因为已经在线程A内执行过3,instance已经是非空了,所以,线程B直接取走了instance,再使用时就会出错。只需要将instance的定义改成private volatile static Singleton instance = null;就可以保证instance对象每次都从主内存中读取。
public class Singleton{
private Singleton(){}
public static Singleton getInstance(){
return SingletonHolder.sInstance;
}
/**
* 静态内部类
*/
private static class SingletonHolder{
private static final Singleton sInstance = new Singleton();
}
}
当第一次加载Singleton类时并不会初始化sInstance,只有在第一次调用Singleton的getInstance方法时才会导致sInstance被初始化。这是推荐使用的单例模式实现方式。
public enum SingletonEnum{
INSTANCE;
public void doSomething(){}
}
默认枚举实例的创建时线程安全的,并且在任何情况下它都是一个单例。枚举不存在反序列化生成新的实例。之前的方式要杜绝单例对象在反序列化时重新生成对象,必须加入如下方法:
//在反序列化提供的钩子函数中将mInstance对象返回。
private Object readResolve() throws ObjectStreamException{
return mInstance;
}
public class SingletonManager{
private static Map<String,Object> objMap = new HashMap();
private SingletonManager(){}
public static void registerService(String key,Object instance){
if(!objMap.containsKey(key)){
objMap.put(key,instance);
}
}
public static Object getService(String key){
return objMap.get(key);
}
}