`

使用static类型产生singleton(单件;单列)模式改善软件设计

阅读更多
这里讨论的是JAVA环境中,使用static关键字实现singleton模式的问题。


singleton模式可以保证对象的实例(如:People p=new People(),People对象的实例p)在其生命周期内是唯一存在的。


      public class Singleton {
      private static Singleton singletonInstance;
      public static Singleton GetSingletonInstance(){
          if(singletonInstance==null){
            singletonInstance=new Singleton();
          } 
             return singletonInstance;
     } 

}


引用
这段代码很好的说明了对象是怎样产生唯一实例的。首先,定义一个静态属性,此属性为这类的引用,在定义一个静态方法,此方法当静态属性为NULL时创建一个对此类的唯一引用,如果此类引用已存在,责直接返回此类所引用的地址。


在非容器环境中:

引用
如果我们来对Singleton类实例化时,此时因为singletonInstance的属性为static,而singletonInstance的属性又定义成了Singleton类的引用,当我们调用GetSingletonInstance静态方法时,首先判断singletonInstance是否为NULL,如果为NULL时直接生存Singleton的实例,并且把地址赋给singletonInstance属性,因为singletonInstance是static的,所以它一直存在于JVM管理的内存之中,只要JVM不停止,程序不被OVER掉,它将一直存在。IF判断结果之后,直接RETURN出singletonInstance。如果这个时候在此调用GetSingletonInstance方法,因为singletonInstance不为NULL,再次return出singletonInstance属性值,此时此实例将唯一,并且长期存在。



使用singleton模式到底能给我们带来什么,很简单,唯一的对象实例,在很多时候有许多东西只能有一个实例存在,数据连接池,线程池,CACHE,日志对象,打印机,显示器驱动等等,这些对象只能存在唯一,不然必定照成系统的数据,动态的混乱。一般来说,我们用Singleton模式来管理需要被共享的资源(类),一般来说,Singleton的类不能有公共构造器,这样使得此类的入口唯一性,保证Singleton类能正确被实例化。这是Singleton的优势所在。但是,Singleton模式也有坏的一面。

JDon论坛有一篇BanQ发表的帖子,很值得注意:地址为;http://www.jdon.com/jivejdon/thread/17578

上面提到了Singleton模式的一些缺点,Singleton用好可以提升性能,用不好带来的性能低下也是显而易见的。甚至太多的Singleton会导致内参泄露,太多的对象一直存在于内存中,因为是STATIC类型的,所以JVM一直不对其进行回收,这些无状态的对象一直游离于系统之中,一旦内存一满,DOWN机,死机是一定会发生的。

在多线层下使用Singleton模式的问题:

这个问题其实比较辣手,一般来说,为了多个线层不对其进行不同访问,我们一般使用synchronized对其加锁,但是使用synchronized对系统性能造成的下降绝对是不可以忽视的,但是我们不使用synchronized好象又没有什么太好的办法,特别是在像WEB系统中,本身展现层就是多线层的环境,有大量的同步或非同步请求,这个时候这么多多线层排列起来,如果用synchronized一锁,那么性能下降1000倍也可能。所以对于多线层使用Singleton必须使用提前加载Singleton,或者使用双重加锁。

引用
不使用延时加载,使用前提加载:


    public class Singleton {

    private static Singleton Instance=new Singleton();

    public static Singleton getInstance(){
          return Instance;
    }

}


引用
使用双重加锁:


public class Singleton {

   private volatile static Singleton Instance;

   public static Singleton getInstance(){
     if(Instance==null){
            synchronized(Singleton.class){
                   if(Instance==null){
                      Instance =new Singleton();
                     }
              }
          }
         return  Instance;
   }

}


关于在容器中使用Singleton模式的问题:

以下原文来自(BANQ)(http://www.jdon.com/jivejdon/thread/31851):

引用
这就涉及容器概念,也就是说,我们将这些对象单例用一个容器包容,不是直接将这些单例放到JVM,而是放到一个容器中,这个容器再放到JVM中;如果我们消灭这个容器对象,那么其中的单例对象就会被GC回收。

这个时候,单例概念已经不是原来JVM单例概念,这个单例是一定范围(时间或空间)内的单例,实际等同于对象的scope。

类似Spring/jdonFramework这样框架,就是引入了这样一个容器,如果我们将这个容器对象scope设置为Web的Application级别,也就是说,在某个Web项目中,这个容器是唯一的,那么容器中的单例对象也就是唯一。如果我们Web项目不再部署,退出,容器对象生命周期结束,其中所有单例对象生命周期也就结束。

注意:虽然我们变通了单例的生命周期,但是在单例有生命时段内,如果多个线程访问(写操作)单例中的状态,那么就有数据不一致问题,好事人如果在这个单例对状态访问操作加上同步锁,那么就可能将多线程的J2EE/JavaEE应用变成单线程。

所以,如果我们的服务或DAO都是无状态的,那么使用单例没有问题,但是谁能保证程序代码不修改,如果来个鲁莽的小伙子,将你的服务改成有状态,那么就出现很多奇怪问题了。

当然,如果你有一个称不上好习惯的习惯,不喜欢在类的字段中保存数据,什么都依赖数据库,那么使用单例也会一直没有问题,但是这种习惯是OO的吗?高负载下性能会好吗?这又涉及另外问题了。

所以,养成用多例Pool来支持你的服务,不失为一个克服上面的两全其美的好办法,但是POOL也有小的性能开销。

其实绕来绕去,我们发现:当初我们使用EJB时的最大困惑:有态和无态的选择,在Spring/jdonFramework中不是被消灭了,而是被转移了,表面简化了,但是这个问题永远回避不了。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics