Chinaunix首页 | 论坛 | 博客
  • 博客访问: 285314
  • 博文数量: 69
  • 博客积分: 2946
  • 博客等级: 少校
  • 技术积分: 800
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-09 04:15
文章分类

全部博文(69)

文章存档

2013年(6)

2012年(16)

2011年(18)

2010年(29)

分类: Java

2013-02-26 23:47:11

在某些应用的场合,一个或者某些类只需要或者只能存在一个实例,这种情况下单例模式便派上了用场。在windows操作系统中,垃圾回收站就是典型的应用,还有很多工程中的配置文件等等,系统中只需要一个实例。当系统需要该类实例时,如果系统中存在该类的实例直接返回实例。如果系统没有该类实例时,创建一个新的类实例,从而保证系统中只存在该对象的一个实例。

系统中类实例创建主要由于其构造方法来完成的,因此在这个时候就需要控制类的初始化过程。下面有两个例子,用不同方式产生所需类的单一实例。

 1:  饿汉式
 2:  public class EagerSingletonPattern {
 3:   
 4:      private static final EagerSingletonPattern ins = new EagerSingletonPattern();
 5:      
 6:      private EagerSingletonPattern(){
 7:      }
 8:   
 9:      public static EagerSingletonPattern getInstance(){
10:          return ins;
11:      }
12:  }

下面便是懒汉式:

 1:  懒汉式
 2:  public class LazySingletonPattern {
 3:      private static LazySingletonPattern ins = null;
 4:      
 5:      private LazySingletonPattern(){
 6:      }
 7:   
 8:      public synchronized static LazySingletonPattern getInstance(){
 9:          if( ins == null){
10:              ins = new LazySingletonPattern();
11:          }
12:          return ins;
13:      }
14:  }

饿汉式在类加载的时候便初始化该类的一个实例,系统需要该类实例时直接返回。在系统调用时响应速度较快,但系统资源利用率较低。懒汉式在需要类实例的时候,先检查系统中是否已经存在类实例。如果存在直接返回,反之创建一个实例。系统资源利用率较高,但在系统调用时响应速度较饿汉式要慢,而且在多线程中,需要线程之间的同步,有可能在资源初始化的时候耗时比较长。

这2种实现方式基本上可以实现所需的要求。但是在懒汉式实现中,后续线程需要等待执行方法线程完成之后才能进入执行,无疑,这延长了系统响应时间。在《Head First 设计模式》书中提到了对懒汉式的一种改进,我个人认为这种方法是正确的,尽管在《Java与模式》书中提到双重检查成例的不正确性。下面我给出《Head First 设计模式》中双重检查加锁的例子。

 1:  public class DCLSingletonPattern {
 2:    
 3:      private volatile static DCLSingletonPattern ins= null;
 4:   
 5:      private DCLSingletonPattern(){}
 6:   
 7:      public static DCLSingletonPattern getInstance(){
 8:          if(ins == null){  //第一重检查
 9:              synchronized(DCLSingletonPattern.class){//线程同步
10:                  if(ins == null){ //第二重检查
11:                      ins = new DCLSingletonPattern();
12:                  }
13:              }
14:          }
15:          return ins;
16:      }
17:  }

volatile关键词确保变量ins在初始化为实例后,多线程能正确的处理ins变量。

上面给出的例子都或多或少都存在一些缺陷,它们的通病都在于其不能被子类所继承。如果能被子类所继承的话,其构造方法至少为protect,而不能为private。但是如果修改成protect,该类就失去了单例模式的特性--其他类可以直接调用其构造方法产生新的实例。因此,在《Java与模式》中给出了登记式的实现方法。但是子类构造方法也不能为private,其构造方法对外开放或部分开放,只能按照登记式实例化可以产生单例,因而也并不完美。在此,我就不给这个例子了,实际应用中,懒汉式和饿汉式基本上够用。

阅读(2264) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~