2008-01-30

设计模式-单例模式(续)

关键字: 设计模式
《设计模式-单例模式》这篇文章中对单例模式做了一个简单的介绍,接下来本文主要讨论的是多例模式、多线程、双重检查以及“不完全”单例类。

一、多例模式
所谓多例模式,实际上就是单例模式之自然推广,单例类一般情况下只可以有一个实例,但单例类也可以推广到允许有限个实例,这种模式就是多例模式,它的主要特点:多例类可以有多个实例。

二、多线程
下面这段代码使用了线程同步,可以说是线程安全的,一个类不会出现多个实例。如果没有synchronized同步,则在单线程中是安全的,但是到多线程中就可能会出现多个实例。
public class LazySingleton        
{        
private LazySingleton m_instance;
private LazySingleton() { }       
  
//对静态工厂方法使用了同步化,以处理多线程环境   关键字synchronized
synchronized public static LazySingleton getInstance()     
{        
   if (m_instance == null)        
   {        
       m_instance = new LazySingleton();        
   }        
   return m_instance;        
  }       
}


三、双重检查
仔细观察一下上面的例子,发现同步只是在m_instance没有被创建之前也就是第一次执行此方法时,明显降低性能。有两种方式可以改善,一就是饿汉式单例模式,另外一种就是双重检查。如下面的代码所示:
public class LazySingleton        
{        
private LazySingleton m_instance;
private LazySingleton() { }       

public static LazySingleton getInstance()     
{        
   if (m_instance == null)//first cheak
   {
       synchronized(this)
       {
         if (m_instance == null)//second cheak
         {
            m_instance = new LazySingleton();
         }
       }        
   }        
   return m_instance;        
  }       
}

但是看了《Java与模式》后才发现这样是不行的,虽然想法是好的!不成立的基本原因在于,在Java 编译器中,LazySingleton 类的初始化与m_instance变量赋值的顺序不可预料。如果一个线程在没有同步化的条件下读取m_instance 引用,并调用这个对象的方法的话,可能会发现对象的初始化过程尚未完成,从而造成崩溃。

但是根据最新的JSR133的java内存模型,如果将引用类型声明为volatile,双重检查模式就可以工作了。如下:
public class LazySingleton        
{        
  private volatile LazySingleton m_instance;//将引用类型声明为volatile
  private LazySingleton() { }       

  public static LazySingleton getInstance()     
  {        
    if (m_instance == null)//first cheak
    { 
       synchronized(this)
       {
         if (m_instance == null)//second cheak
         {
            m_instance = new LazySingleton();
         }
       }        
    }        
    return m_instance;        
  }       
}


四、不完全单例类
如下面的代码所示,看起来好像是懒汉式单例类,但是细看一下,才发现没有隐藏构造函数。这就是不完全单例类。
public class LazySingleton 
{ 
  private static LazySingleton 
  m_instance = null; 
  /** 
  * 公开的构造子,外界可以直接实例化 
  */ 
  public LazySingleton() { } //注意:这里是public
  /** 
  * 静态工厂方法 
  * @return 返还LazySingleton 类的惟一实例 
  */ 
  synchronized public static LazySingleton getInstance() 
  { 
    if (m_instance == null) 
    { 
      m_instance = new LazySingleton(); 
    } 
    return m_instance; 
  }
}
评论
发表评论

您还没有登录,请登录后发表评论

ldjsyl
搜索本博客
我的相册
C64aa706-46c3-3a75-8cd1-1d72023decc4-thumb
新建 BMP 图像
共 12 张
存档
最新评论