背景、
单例模式是应用最广的模式之一,也很可能是很多初级工程师唯一会使用的设计模式,在应用这个模式的时候,单例对象的类必须保证只有一个实例存在,许多时候整个系统只需要一个全局对象,这样有利我们协调系统的整体行为,如在一个应用中,应该只有一个ImageLoader实例,这样ImageLoader中既有线程池,缓存系统,网络请求等,很消耗资源,因此,没有理由让它有很多个实例。
一、使用场景及思想
确保某个类中只有一个实例,且自行实例化并向系统提供这个实例
思想单例模式的几个关键点
1.构建函数不能对外开放,一般为Private。
2.通过一个静态方法返回实例化对象。
3.确保单列类只有一个,尤其是在多线程的情况下。
4.确保实例类对象在反序列化时不会重写构建。
二、饿汉单列模式
public class Instance {
private static final Instance instance=new Instance();
private Instance(){
}
public static Instance getInstance(){
return instance;
}
}
三、懒汉的加载模式
public class Instance1 {
private static Instance1 instance;
private Instance1(){
}
public static synchronized Instance1 getInstance(){
if (instance==null) {
instance=new Instance1();
}
return instance;
}
}
可以发现getInstance方法中加了synchronized 关键字,也就是一个同步方法,这就是在上面说的在多线程情况下保证单列对象的手段,但是你会发现一个问题,及时instance被初始化每次调用的时候都会进行同步,这样会消耗不必要的资源,这个也是懒汉模式存在的问题大量地消耗资源,造成不必要的开销 。
四、Double Check Lock实现单列模式
public class Instance2 {
private static Instance2 instance;
private Instance2(){
}
public static synchronized Instance2 getInstance(){
if(instance==null){
synchronized (Instance2.class) {
if (instance==null) {
instance=new Instance2();
}
}
}
return instance;
}
}
双层判空第一层是为了避免不必要的同步,第二层是判断在null的情况下创建实例,这样的优点为 资源利用率高,第一次执行的时候单例对象才会被实例,效率高,如果不为null减少同步消耗资源直接返回这个单例。,缺点是第一次加载的时候反应比较慢,但是这个是模式是使用最多的单列方式,它能在需要的时候才加载实例化对象,并且在大多数情况下都可以保证唯一性。
五、使用容器实现单列模式
public class InstanceManager {
private static Map<String, Object> objMap= new HashMap<String,Object>();
private InstanceManager(){
}
private static void registerManager(String key,Object object){
if (!objMap.containsKey(key)) {
objMap.put(key,object);
}
}
public static Object getService(String key){
return objMap.get(key);
}
}
在程序开始将多种类型注入管理类中,在使用时根据key获取对象对应类型的对象,这种方式使我们可以管理多种类型单列,并且可以通过统一的接口进行获取操作,减低了用户的使用成本,也对用户隐藏了具体实现,减低了耦合度
六、总结
不管以何种形式实现单例模式,它们的核心原理都是将构造方法私有化,并且通过静态方法获取一个唯一的实例,在这个获取的过程中必须保证线程安全,防止反序列化导致重新生成实例化对象等问题,我个人推荐使用双层锁判断