[总结]设计模式之-单例模式

 

      今天是在中科院创思分校上课的第一天,有很多的感悟,很多都是惊愕自己以前的思想的污点。
       以前的我有点忽视基础知识的重要性,总认为自己的基础知识比较强大,但是在中科院听课一个小时后我猛然发现自己的基础原来是那么的不系统,不全面,不够深入。这也是我今天感觉到比较惊愕的原因,我想不到比较好的词语来形容我的心情,只能用这个词,我认为这个词才能表示出我的那种后怕而带有点庆幸的心情。这边的老师讲课确实比较系统也比较详细,例子也比较经典,我真后悔当初怎么不早点来到这个学校进行系统的学习,这样我就少走好多的弯路。(注:本人不是枪手)
       上面的是我今天上课的感想,下面的也是我昨天所说的我的设计模式交流平台,希望大家看到后不要见笑,共同交流,共同提高。
步入正题:设计模式之-singleton单例模式
       在很多的设计中,我们在控制整个JVM中只能生成出某个并且仅仅是一个对象的时候,会采用这种模式,比如在整个软件的运行期间不能显示多个界面这样的形式,从术语来说就是:在整个JVM中只能实例化出一个这样的对象。
       菜鸟在设计这样的模式的时候往往会用到一个static计数器来实现判断后在定义是否加载新的对象,但是仔细想想其实这样也是行不通的,特别是在高并发的情况下其垃圾性令人发指。
       1.很多的人总是想将类的实例化让自己来手动控制,简单的说就是将类的实例化给自己来判断后再通过业务逻辑来进行实例化,熟不知这样给程序带来很高的不可靠性的同时,也令自己思维承受更多的考验,“没有完美的程序”这条“天条”时刻考验着敲打代码的我们,总担心什么时候出现不可预料的问题。
       2.既然最好不要自己来控制类的实例的分配,那么将类的加载或者实例放到类中,让它自己在自己的内部进行判断和分配。
举个通俗的例子:
一女子出嫁只能出嫁一次(女子也为唯一),如果让父亲(非本人)来控制女儿婚配的话,那么父亲可能会面临着众多“女婿”的追求和请帖,作为父亲他将承受着众多人的压力和他要强迫自己做出很多的判断,(可能到最后父亲竟答应了两个人的婚姻约定),这种由父亲包办的婚姻彻底与女儿脱钩,那么最好的方式是:让女儿自己来选择自己的如意郎君,这样即安全又稳妥的解决了父亲劳累的问题,嫁给谁和只嫁一次的问题都妥善解决,何乐而不为?

通过以上的例子,我们对单例的管理模式进行了分析,总结为:让单例类自己来控制实例化或加载的顺序和方式,避免多线程并发的时候产生的不一致问题。
下面我们来看看最简单的单例示例程序:
  1. public class Singleton    {    
  2.     private static final Singleton singleton = null;      
  3.     private Singleton()        {    
  4.     }        public static Singleton getInstance()    
  5.     {            if (singleton== null)    
  6.         {                singleton= new Singleton();    
  7.         }            return singleton;    
  8.     }    }  
私有(private)的构造函数是为了不让别人进行显式的实例化:类似new Singleton()来实例是不允许的
特别注明:static final Singleton singleton = null;中有人会认为final关键字会导致不能加载,这样想是及其错误的,final对于引用来说知识锁定引用,但是对于引用的内存还是可以进行修改的,因为他不像是对stack中的数据进行修改的时候一样。
总结一:上述的单例模式中可以实现很基本的单例,可以通过Singleton.getInstance()来获取一个对象,第二个请求进来的时候先判断是否已经示例化了,然后进行分配或者实例.缺点是如果在高并发多线程的情况下,这种就会完全失效,假设两个线程都通过了第10行的空检测,那么拿出来的还是两个对象,没有起到单例的作用,所以有了第二个版本,如下所示:

  1. public class Singleton    {    
  2.     private static final Singleton singleton = null;      
  3.     private Singleton()        {    
  4.     }        public static Singleton getInstance()    
  5.     {            if (singleton== null)    
  6.         {                synchronized (Singleton.class) {    
  7.                 singleton= new Singleton();                }    
  8.         }            return singleton;    
  9.     }    }    

synchronized 的用法相信在学过线程同步的时候都会知道是什么意思,此种解决方案在进行低并发的时候还是可以勉强起作用,但是还是会有可能出现类似第一个例子中所出现的实例出两个对象的情况,并且只是将第一种同时实例化出两个对象,改变成了按照一定的顺序串行实例出两个对象,其结果当然不是我们想要的。

既然在第二个例子中我们想到了多个线程碰运气跳过第一到空判断以后会以串行的方式实例对象,那么我们能不能以再次判断空的方式进行实例化呢,由于是一堆的线程进行排队领取,当Date Segment中的singleton引用指向的不为空的时候将不再实例化,如果为空则表明当前那一堆线程中已经有人申请到了一个对象,所以后面的都不予考虑,所以按照此思维会有如下的代码:


    • public class Singleton    

    • {    
    •     private static final Singleton singleton = null;      
    •     private Singleton()        {    
    •     }        public static Singleton getInstance()    
    •     {            synchronized (Singleton.class)    
    •         {                if (singleton== null)    
    •             {                    singleton= new Singleton();    
    •             }            }    
    •         return singleton;        }    
    • }   在12行将类加锁,让访问的线程串行化,从而对排队的线程进行有序的单个的判断,这样就解决了单例中的并发问题,呼呼,在此一个像模像样的单例就已经成功了,不过为了解决加锁对于性能的一些影响,我们还是会采用如下的方式来控制实例化,仅仅多了一行代码:

      1. if(singleton==null){       synchronized (Singleton.class)    
      2.         {                if (singleton== null)    
      3.             {                    singleton= new Singleton();    
      4.             }            }}  
      5.         return singleton;  
      如上所示的第一行的判断会将以后所有的线程拒之门外,这样对服务器的性能提高将是非常的高的。

      到此对于单例的代码重用一直是个问题,所以不得不在有些时候做出点牺牲,总之单例模式在某些时候还是需要的,在某些特别需要的业务逻辑上还是有必要的,希望大家能够和我交流学习,批评指正。
      期待下一期的新作 设计模式之-工厂模式
    • 0
      点赞
    • 0
      收藏
      觉得还不错? 一键收藏
    • 0
      评论
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值