介绍
单例模式是设计模式中比较简单的,也是老生常谈的一个话题;全局只有一个单例类,即没有其他的层次结构与抽象,全局只存在一个实例话对象.
实现方式
-
懒汉模式
public class SingleInstance{
private static SingleInstance singleInstance;
public static synchronized SingleInstance getInstance(){
if(singleInstance==null){
singleInstance=new SingleInstance();
}
return singleInstance;
}
}
此处利用Synchronized同步方法,保证其在多线程环境下的唯一性,不过有一个问题那就是每次调用getInstance()都会进行同步,这样就会造成不必要的资源浪费;所以一般不建议使用这种模式.
-
DCL方式
public class SingleInstance{
private static SingleInstance singleInstance;
public static SingleInstance getInstance(){
if(singleInstance==null){
synchronized(SingleInstance.class){
if(singleInstance==null){
singleInstance=new SingleInstance();
}
}
}
return singleInstance;
}
}
相对于懒汉模式我们在这里进行了两处更改
1. 我们将Synchronized同步实现方式改变了
2. 我们在同步锁的外层添加了一层判断
经过了这两处的改变我们既规避了不必要的同步而带来的资源浪费,提升了资源的利用率,又保证了线程安全;但还是会存在一定的缺点,例如:第一次加载时反应稍慢会由于Java模型的原因造成偶尔的失败,同样在高并发环境下也有存在缺陷,但能够在绝大场景下保证单例的唯一性.
-
静态内部类单例模式
public class SingleInstance{
private static SingleInstance singleInstance;
public static SingleInstance getInstance(){
return singleInstanceTask.mSingleInstance;
}
/**
*静态内部类
*/
private static class SingleInstanceTask{
private static final SingleInstance mSingleInstance=new SingleInstance();
}
}
虽然DCL可以解决大多数场景下单例对象的唯一性但是依然存在问题,这种问题被称为双重检查锁定失效;而静态内部类单例模式这种方式不仅能够保证线程安全也可保证单例对象的唯一性,同时也延迟了单例对象的实例化.
-
枚举单例模式
public enum SingleInstance{
INSTACNE;
}
枚举的写法很简单;枚举在多线程环境下是安全的,为什么这样说呢?这其中涉及到反序列化的问题;我们普通的单例模式都是通过序列化将实例对象写到磁盘,然后再通过反序列化重新生成一个新的对象进行读取,从而有效的获取一个实例对象,而对于枚举单例对象即使反序列化也不会重新生成的实例.
-
使用容器实现单例
public class SingleInstanceManager{
private static Map<String,Object> singleMap=new HashMap<String,Object>();
public static void putSingleMap(String key,Object value){
if(!singleMap.containsKey(key)){
singleMap.put(key,value);
}
}
public static Object getSingleValue(String key){
return singleMap.get(key)
}
}
这种方式可以成为管理多个单例对象的容器,统一调用接口降低耦合度.
总结
单例模式的核心是为了保证全局的对象唯一性,并且要保证对象的多线程环境下的安全、防止反序列化导致的重新生成对象等问题.
网友评论