设计模式之单例模式(singleton)

单例模式的定义

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

一个简单Java实现

public class Singleton {
 private static Singleton instance;
 
 private Singleton() {
 }
 
 public static Singleton getInstance() {
 
   if(instance == null) {
     instance = new Singleton();
   }
   return instance;
 }
}

在上述Java实现中,单例对象保存在一个类静态对象,类的构造函数声明为私有,要想使用这个类,必须调用getInstance方法获取全局唯一的静态单例对象。

这个简单的方法主要的缺点是没有考虑到多线程的情况,在多线程运行过程中,很有可能多个线程一开始同时进入getInstance方法,从而使得单例对象被初始化多次,线程获取到的单例并不一致。

一个解决方法是将getInstance方法声明为线程同步,请看下面的样例。

多线程同步实现创建单例

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

上述Java实现中,getInstance方法声明为线程同步,其避免了多线程一开始同时调用该方法而导致的多次实例化问题。但是这个解决方案并不完美,问题就出在线程同步上,在简单应用上这个缺点表现不明显,但是如果是多线程应用,getInstance方法被频繁调用的话,所有线程会在进入getInstance方法排队等待,线程调用会被频繁切换,造成不必要的系统资源消耗。

其实线程同步主要是希望在最开始的几个线程访问getInstance方法时,一旦单例对象创建完毕后,就不再需要让每个线程等待依次进入该方法,换句话说,单例创建完毕后,各个进程就可以异步访问该方法,获取已创建的单例对象。

优化后的解决方案见下面的样例。

多线程的异步获取和同步创建单例

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

上述Java实现中,静态单例对象被声明为volatile对象,其意义是这个对象为各个线程共享对象,JVM不再为每个线程执行时在内存复制该对象。getInstance方法的访问是异步的,各个线程的访问独立运行,如果已有单例对象,则直接获取并退出getInstance方法;如果单例对象为空,则创建过程对线程同步,保证只让第一进入该代码块的线程来初始化该单例。

通过JVM的静态初始化来创建单例

如果系统的启动资源足够用,可以让单例的创建放在JVM启动中,即通过静态初始化器(static initializer)来创建单例,

public class Singleton {
 private static Singleton instance = new Singleton();
 
 private Singleton() {
 }
 
 public static Singleton getInstance() {
   return instance;
 }
}

上述方法简单实用。

代码样例

代码仓库地址:http://git.oschina.net/pphh/designPatterns,可以通过如下git clone命令获取仓库代码,

git clone git@git.oschina.net:pphh/designPatterns.git

上述代码样例在文件路径designPatterns\java\singleton中。

参考资料

《设计模式-可复用面向对象软件的基础》

《Head First 设计模式》

百度百科:http://baike.baidu.com/view/1859857.htm

发表评论

邮箱地址不会被公开。 必填项已用*标注

*

code