[转帖]设计模式——单例模式_OpenStack, 云计算等杂项讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  OpenStack, 云计算等杂项讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 5032 | 回复: 0   主题: [转帖]设计模式——单例模式        上一篇   下一篇 
weiwei.fu
注册用户
等级:上尉
经验:661
发帖:47
精华:0
注册:2013-12-12
状态:离线
发送短消息息给weiwei.fu 加好友    发送短消息息给weiwei.fu 发消息
发表于: IP:您无权察看 2013-12-13 14:45:08 | [全部帖] [楼主帖] 楼主

经典的设计模式之单例设计!!!
参考原文来自

 http://blog.csdn.net/singwhatiwanna/article/details/17056901


为什么需要单例模式



有时候我们需要使用一个实用类A,这个类A专门提供一些公共功能供别人调用,而本身并不会处理业务逻辑。由于类A会被许多类乃至线程调用,假设我们的程序非常庞大,在运行的过程中,会访问这个类A100次,为了调用类A的方法,需要先创建A的对象,A a = new A()。这种方法在对A的访问量较少的情况下没问题,但是像我们这种情况,就会创建100个类A的实例,这100个实例是要占用内存的,从这种角度来说,就造成了大量不必要的开销。而单例模式,在整个程序生命周期中,只有一个实例,这样就不会造成不必要的内存消耗。

单例模式的设计



为了让整个生命周期内只有一个实例,我们可以这样做:

[java]view plaincopy北京联动北方科技有限公司北京联动北方科技有限公司

  1. public class Singleton { 
  2.       
  3.        private static Singleton sSingleton; 
  4.       
  5.        private Singleton() { 
  6.        } 
  7.       
  8.        public static Singleton getInstance() { 
  9.              if (sSingleton == null) { 
  10.                    sSingleton = new Singleton(); // line A 
  11.              } 
  12.             
  13.              return sSingleton; 
  14.        } 
  15.       


上述做法好像没啥问题,由于mSingleton是静态的,因此能够保证程序运行过程中只存在一个实例。但是针对多线程情况,就可能有问题,比如有2个线程同时并发调用getInstance方法,并且同时执行到了line A,这个时候还是会各自new一个对象出来,也就是说,存在了两个实例,这违背了单例模式的概念,下面我们改进一下:

[java]view plaincopy北京联动北方科技有限公司北京联动北方科技有限公司

  1. public class Singleton { 
  2.       
  3.        private static Singleton sSingleton; 
  4.       
  5.        private Singleton() { 
  6.        } 
  7.       
  8.        public static Singleton getInstance() { 
  9.              synchronized (Singleton.class) { 
  10.                   
  11.                    if (mSingleton == null) { 
  12.                          sSingleton = new Singleton(); 
  13.                    } 
  14.                    return sSingleton; 
  15.              } 
  16.             
  17.        } 
  18.       


上述做法的确是没啥问题了,getInstance方法中对Singleton.class加锁,可以保证同一时刻只有一个线程能够进入getInstance方法。现在考虑一种情况,还是我们的比较庞大的工程,在某个变态的时刻,我们需要访问Singleton对象100次,注意是高并发下的同时访问,会是什么情形呢?大概是这样的:100个线程进入getInstance方法以后开始抢mSingleton的所有权,这个时候,有一个线程获得了锁,然后顺利地得到了Singleton实例,接着会是什么情形呢?应该是这样的:剩下99个线程开始抢mSingleton的所有权,一直这样类推下去,可能有一个线程运气比较差,抢了100次才抢到锁,程序的表现可能是这样的:这个运气差的线程被阻塞在getInstance方法中,迟迟无法返回,如果需要返回数据给ui的话,那么ui将迟迟不会得到更新。

我们需要看一下上述代码,真的需要每次进入getInstance方法都要获得锁吗?其实不是的,整个Singleton类中,对mSingleton进行访问的地方分为两类:读和写,而且仅当mSingleton为null的时候才会写,mSingleton一旦创建完毕,后面就只剩下读操作了,再怎么高并发也没什么关系了,反正mSingleton已经是现成的,直接读就可以了,看如下采用double-check机制的改进代码:

[java]view plaincopy北京联动北方科技有限公司北京联动北方科技有限公司

  1. public class Singleton { 
  2.       
  3.        private volatile static Singleton sSingleton; 
  4.       
  5.        private Singleton() { 
  6.        } 
  7.       
  8.        public static Singleton getInstance() { 
  9.              if (sSingleton == null) { // line A 
  10.                    synchronized (Singleton.class) { // line C 
  11.                          if (sSingleton == null) 
  12.                          sSingleton = new Singleton(); // line B 
  13.                    } 
  14.              } 
  15.             
  16.              return sSingleton; 
  17.        } 
  18.       


上述代码近乎完美,可以满足几乎所有场合(采用反射和类加载器另当别论)。上述代码的好处在于:第一次创建实例的时候会同步所有线程,以后有线程再想获取Singleton的实例就不需要进行同步,直接返回实例即可。还有double-check的意义在于:假设现在有2个线程A和B同时���入了getInstance方法,线程A执行到line A行,线程B执行到line B行,由于B线程还没有初始化完毕,sSingleton还是null,于是线程A通过了sSingleton==null的判断,并且往下执行,碰巧,当线程A执行到line C的时候,线程B初始化完毕了,然后线程B返回,注意,如果没有double-check,这个时候线程A就执行到了line B,就会再次初始化sSingleton,这个时候Singleton实际上被new了两次,已经不算完全意义上的单例了,而有了double-check,就会再进行一次为null的判断,由于B线程已经初始化了sSingleton,所以A线程就不会再次初始化sSingleton。




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论