设计模式学习之--Singleton(单例)模式

首先我们先看看一个例子,在说什么是单利模式(Singleton):

Java代码   收藏代码
  1. package  org.bestupon.dp.singleton;  
  2. /**  
  3.  
  4. * @author BestUpon  
  5. * @email bestupon@foxmail.com  
  6. * @date 2010-6-13上午11:08:28  
  7. * @ask jdk中Runtime这个类似就是一个单例模式的应用:  
  8.  
  9. * @answer  
  10. */   
  11. public   class  Test4RunTime {  
  12.   
  13. public   static   void  main(String[] args) {  
  14. Runtime runtime = Runtime.getRuntime();  
  15. runtime.freeMemory();  
  16. }  
  17. }  

上面的例子可以看出在没有使用new,却获得了一个Runtime对象,这是为什么呢?让我们看看java.lang.Runtime.java的源码到底是怎么一回事:

Java代码   收藏代码
  1. public   class  Runtime {   
  2.     private   static  Runtime currentRuntime =  new  Runtime();   
  3.     public   static  Runtime getRuntime() {   
  4.         return  currentRuntime;   
  5.     }   
  6.    /** Don't let anyone else instantiate this class */    
  7.    private  Runtime() {}   
  8.     // 以下略    
  9. }  

 以上是Runtime.java开头部分的代码,我们可以很清楚的看见,一开头就直接 new Runtime(), 一个对象,并且是静态的。在getRuntime()的时候,

直接将其返回给请求的客户端。   上面结构即采用 Singleton 模式设计,其结构使用 UML 描述 如下所示:


Singleton 的英文意义是独身,也就是只有一个人,应用在面向对象语言上,通常翻译作单例:单一个实例( Instance )。 Singleton 模式可以保证一个类别 只有一个实例,并只提供一个访问( visit )这个实例的方法。

1. 定义: 单例模式就是确保一个类中只有一个实例,并且该实例必须自动创建,并向整个系统提供该实例。

2. 使用时机: 当系统要求一个类只有一个实例时,就需要使用用单例模式。

 

有几个实例上面结构的方法,可以在第一次需要实例时再建立对象,也就是采用所谓的 Lazy Initialization

 

Java代码   收藏代码
  1. public   class  Singleton {   
  2.     private   static  Singleton instance =  null ;   
  3.     private  Singleton() {   
  4.         // ....    
  5.     }   
  6.     public   static  Singleton getInstance() {   
  7.         if  (instance ==  null ) {  
  8.             instance = new  Singleton();   
  9.         }  
  10.         return  instance;   
  11.     }   
  12.   
  13.     // .. 其它实例    
  14. }  

  上面的实例适用于单线程的程序,在多线程的程序下,以下的写法在多个线程的竞争资源下,将仍有可能产生两个以上的实例,例如下面的情况:

 

Java代码   收藏代码
  1. Thread1:  if (instance ==  null// true   
  2. Thread2: if (instance ==  null// true   
  3.   
  4. Thread1: instance = new  Singleton();  // 产生一个实例   
  5. Thread2: instance = new  Singleton();  // 又产生一个实例   
  6.   
  7. Thread1: return  instance;  // 回传一个实例   
  8. Thread2: return  instance;  // 又回传一个实例   

  在多线程的环境下,为了避免资源同时竞争而导致如上产生多个实例的情况,加上同步( synchronized )机制:

 

Java代码   收藏代码
  1. public   class  Singleton {  
  2.       private   static  Singleton instance =  null ;  
  3.       private  Singleton(){}  
  4.       synchronized   static   public  Singleton getInstance() {  
  5.           if  (instance ==  null ) {  
  6.               instance = new  Singleton();  
  7.           }  
  8.           return  instance;  
  9.       }  
  10.   }  

  不过这种简单的写法不适合用于像服务器这种服务很多线程的程序上,同步机制会造成相当的效能低落,为了顾及 Singleton Lazy Initialization 与效能问题,因而有了 Double-check Locking 的模式:

 

Java代码   收藏代码
  1. public   class  Singleton {  
  2.       private   static  Singleton instance =  null ;  
  3.       private  Singleton(){}  
  4.       public   static  Singleton getInstance() {  
  5.           if  (instance ==  null ){  
  6.               synchronized (Singleton. class ){  
  7.                   if (instance ==  null ) {  
  8.                        instance = new  Singleton();  
  9.                   }  
  10.               }  
  11.           }  
  12.           return  instance;  
  13.       }  
  14.   }  

  也就是只有在第一次建立实例时才会进入同步区,之后由于实例已建立,也就不用进入同步区进行锁定。 Java Runtime 类别的作法简单的多, 它舍弃了 Lazy Initialization ,如果您要取得单例的机会不是很多,可以用这种方式:

 

Java代码   收藏代码
  1. public   class  Singleton {   
  2.     private   static  Singleton instance =  new  Singleton();   
  3.     private  Singleton() {   
  4.         // ....    
  5.     }   
  6.     public   static  Singleton getInstance() {   
  7.         return  instance;   
  8.     }   
  9.     // 其它实例    
  10. }  

  Singleton 本身的观念简单但应用 很广,因而很多时候必须对实际环境作一些考虑与调整。

3.总结:

单例模式可以分为两种:饿汉式和懒汉式两种,饿汉是在系统启动的一开始就初始化好了实例,而懒汉式是在第一次访问的时候才初始化实例。

 

Java代码   收藏代码
  1. package  org.bestupon.dp.singleton;  
  2.   
  3. /**  
  4.  * @author BestUpon  
  5.  * @email bestupon@foxmail.com  
  6.  * @date 2010-6-13上午11:34:27  
  7.  * @ask 饿汉式单利模式  
  8.  * @answer  
  9.  */   
  10. public   class  HungerSingleton {  
  11.   
  12.     /**  
  13.      * 一开始就初始化好了实例  
  14.      */   
  15.     private   static  HungerSingleton instance =  new  HungerSingleton();  
  16.   
  17.     private  HungerSingleton() {  
  18.     }  
  19.   
  20.     public   static  HungerSingleton getInstance() {  
  21.         return  instance;  
  22.     }  
  23.   
  24. }  

 package org.bestupon.dp.singleton;

Java代码   收藏代码
  1. /**  
  2.  *   
  3.  * @author BestUpon  
  4.  * @email bestupon@foxmail.com  
  5.  * @date 2010-6-13上午11:41:22  
  6.  * @ask 懒汉式单例模式  
  7.  * @answer  
  8.  */   
  9. public   class  LazySingleton {  
  10.     private   static  LazySingleton instance =  null ;  
  11.   
  12.     private  LazySingleton() {  
  13.     }  
  14.   
  15.     public   static  LazySingleton getInstance() {  
  16.         if (instance ==  null ){  
  17.             instance = new  LazySingleton();  
  18.         }  
  19.         return  instance;  
  20.     }  
  21. }  

4.优点:

在单利模式中,客户调用类的实例时,只能调用一个公共的接口,这就为整个开发团队提供了共享的概念,

5.缺点:

单利模式在实例化后,是不允许类的继承的;在分布式系统中,当系统的单利模式类被复制运行在多个虚拟机下时,在每一个虚拟机下都会创建一个实例对象,此时如果想知道具体哪个虚拟机下运行着单例对象是很困难的,而且单例类是很难实现序列化的。

 

 

 

由于端午节放假的缘故,各位同仁在期间提出了很多的问题,也指出了我思维的局限性,没有及时的更新于回复各位好友的,深表遗憾!


针对单例模式的很多用法,前面一直是在所单一线程的问题,本来设计多线程的问题就很少,也对双重锁定这个问题没有深入的五挖掘,导致了犯了今天这样的错误。 之后参考了一些资料,针对各位朋友提出的问题与我自身存在的问题,进行改进! 参考的文章是:IBMDeveloperWorks(中国)的网站上的文章 双重检查锁定及单例模式 http://www.ibm.com/developerworks/cn/java/j-dcl.html )。这篇文章真针对各种问题都有分析,包括可见性等问题。得出了一个结论:双重锁定失效的主要原因是:不同JVM之间的无序写入问题,多线程之间的独占、休眠(记忆复苏)所引起的不同 不问题。

最终本文提出了一个建议: 议不要使用“双重锁定”! 一个解决单例模式的方案:

底线就是:无论以何 种形式,都不应使用双重检查锁定,因为您不能保证它在任何 JVM 实现上都能顺利运行。JSR-133 是有关内存模型寻址问题的,尽管如此,新的内存模型也不会支持双重检查锁定。因此,您有两种选择:

  • 接受如清单 2 中所示的  getInstance()  方法的同步。
  • 放弃同步,而使用一个  static  字段。

选择项 2 如清单 10 中所示:

 

Java代码   收藏代码
  1. /**  
  2. *<span style="font- family: verdana, nsimsun, sans-serif; white-space: normal; line- height: 19px;"><a style="color: #5c81a7;" name="code10">< strong>使用 static 字段的单例实现</strong></a></span>  
  3. **/   
  4. class  Singleton  
  5. {  
  6.   private  Vector v;  
  7.   private   boolean  inUse;  
  8.   private   static  Singleton instance =  new  Singleton();  
  9.   
  10.   private  Singleton()  
  11.   {  
  12.     v = new  Vector();  
  13.     inUse = true ;  
  14.     //...   
  15.   }  
  16.   
  17.   public   static  Singleton getInstance()  
  18.   {  
  19.     return  instance;  
  20.   }  

转自JAVAEYE
谢谢
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值