单例设计模式

 前两天写了设计模式总纲,今天就来讲讲我们在工程代码中最最最常用的设计模式了——单例设计模式,这个模式在工程代码上的出现率几乎为99.99999%,但是虽然很常用,但是用的好的人却不多,今天我们就来深入的说一说单例设计模式。

  在学习一项新的知识之前,我们都要向自己提出三个问题,为什么要用这个知识,这个知识用在哪里,这个知识怎么用?既 why,where,how,3W模式,我们先来谈谈为什么需要单例设计模式,先来想想,如果一个工具类,比如一个读取配置文件的工具类,这类工具只是特定的功能类,既读取指定的文件内容,这种类我们在使用的时候只需要建造一个就行了,然后在整个系统之中都用这个类来进行指定文件的读取即可,但是如果在设计之初没有考虑好,并没有把其设计成单例,导致整个系统中分布多个类似的功能类,一方面,导致了系统资源的浪费,如果该配置文件内容较小,对内存来说还好,但是如果是几百M或者几个G的配置文件的内容的话,就会造成系统资源的严重浪费,导致内存泄露,一方面也会让代码显得异常凌乱。

  为了解决这种问题,既对于只是解决单一功能的功能类,我们最好的做法就是将其设计成单例,接下来我们来看看我们要怎么来实现一个单例。

  正所谓万丈高楼平地起,再复杂的功能也是由一行行简单的代码组成的,那我们来看一下,要实现一个单例类的话,首先,肯定是不能让用户自行生产的,那就是说明不能让用户new,所以,就必须把构造函数设置成为私有的。

1 public class Singleton {2     private Singleton(){}3 }

好了,这就是单例了,哦,不,这应该是无例,因为把构造函数都弄成私有的了,什么都没有,用户拿到了这个类只能一脸懵逼,既然要变成单例,那肯定要给用户一个实例是吧,既然用户创建不了,那我们就给他一个,如下

 1 public class WorstLazySingleton { 2     //1、私有化构造函数 3     private WorstLazySingleton(){} 4      5      //2、静态化一个实例,静态的实例保证了在每一个类中都是唯一的 6     private static WorstLazySingleton instance = null; 7      8      9     //3、返回该对象的实例,也必须是静态的方法,不然无法调用静态的实例10     public static WorstLazySingleton getInstance(){11         if(instance == null){12             instance = new WorstLazySingleton();13         }14         return instance;15     }16 }

好了,一个新鲜的单例就出炉了,but,是不是有什么问题呢,为什么这个单例被加上了个Worst的标签,这个年代什么最惨,被人随意贴标签最惨,隔着屏幕都能感受到这个单例哀怨的眼神,但是,我们来看一看,这个单例,咋一看在单线程的环境下没问题,但是只要一到了多线程的环境下,妥妥的要出问题啊,随意写了个测试用例,跑了个10条线程来getInstance,竟然出现了4个不一样的hashCode,这个哪里是单例,明显是多的不能再多的”多例“了,好吧,这个worst的标签就先贴上去吧。那有同学就说了,我加同步方法啊,好,我们来为这个类加上同步方法,

  大致如下代码,

         BadLazySingleton instance =                //加上了synchronized的同步方法                (instance ==              instance =             }

 

这个方法现在被加上了synchronized了,运行一下多线程的测试环境,咋一看,好像没问题了,但是,我们再想一下下面的场景,如果在方法里面这个对象特别大的话,导致虚拟机调用的时间较长,或者在这个方法里面做了其他的 doSomething()方法的话,那其他线程只能乖乖的等待他的结束了,比如这个 方法执行时间用了10S,那10条线程过来,想想就有点小激动呢,一旦运行在服务器端上,那客户的等待时间,流失率是妥妥的,又有同学要提意见了,我们可以来缩小范围啊,我们不要再在方法上加同步了,好,那我们来看一看下个version的单例,

单例设计模式