转载

设计模式之单例模式

单例模式(Singleton) —— 对象创建型模式

本文记录单例模式从设计理念的简单到复杂,从运行效果的低效到高效,各种不同实现方式。涉及到多线程和JVM。

定义

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

The Singleton Pattern ensures a class has only one instance, and provides a gloable point of access to it.

类图

设计模式之单例模式

实现

实现一:最简单,线程不安全。

/**  * @description 最简单的实现,线程不安全。  * @author michael  */ public class Singleton {  private static Singleton uniqueInstance;  //Other useful Singleton data...  /**   * 构造器私有化   */  private Singleton() {  }  /**   * @description 抽象工程方法(static factory),获得该类唯一实例。   * @return 唯一实例   */  public static Singleton getInstance() {   if(null == uniqueInstance) {    uniqueInstance = new Singleton();   }   return uniqueInstance;  }  //Other useful Singleton methods... } 

实现二:同步方法

使用synchronized关键字,同步getInstance()方法,确保任意时刻只有一个线程可以访问该方法。线程安全,效率低。

/**  * @description 线程安全,效率低。  * @author michael  */ public class Singleton {  private static Singleton uniqueSingleton;  //Other useful Singleton data...  /**   * 构造器私有化   */  private Singleton() {  }  /**   * @description 同步方法,线程安全,效率低。   * @return 唯一实例   */  public static synchronized Singleton getInstance() {   if(uniqueSingleton == null) {    uniqueSingleton = new Singleton();   }   return uniqueSingleton;  }  //Other useful Singleton methods... } 

实现三:饿汉式

先于方法调用前创建实例,静态初始化变量。依赖于JVM的实现,虚拟机要确保在任何线程访问静态变量uniqueSingleton之前创建好实例。

/**  * @description move to an eagerly created instance rather than a lazily created one.  * @author michael  */ public class Singleton {  private static Singleton uniqueSingleton = new Singleton();  //Other useful Singleton data...  /**   * 构造器私有化   */  private Singleton() {  }  /**   * @description eagerly created   * @return 唯一实例   */  public static synchronized Singleton getInstance() {   return uniqueSingleton;  }  //Other useful Singleton methods... } 

实现四:双检测

使用volatile关键字修饰变量,确保多线程访问修改正确。双检测,只有在第一次调用getInstance()才会同步类。 版本要求:JDK1.5或以上。

解释下为什么需要双重检测,假设此时uniqueSingleton == null,两个线程同时调用getInstance()方法,由于uniqueSingleton还未创建,

if条件满足, 两个线程都会进入if语句内部。但是下一步只有一个线程会拿到锁,进入到同步代码块,此时再次检测依然为空,创建实例,

释放锁,并返回实例。 当另一个线程获得锁进入同步代码块时,实例已创建,释放锁返回实例。这是双重检测的情况,如果不在同步块内二次检测,

同样两个线程同时访问 getInstance()方法, 在if语句内, 同步方法块外堵塞。获得锁的线程创建实例、释放锁并返回实例。当另一个线程获得锁执行同步代码时,

没有进行二次 检测,尽管此时uniqueSingleton已经被创建,后获得锁的线程依然会再创建一个实例,违反了唯一实例的原则。

/**  * @description double checked  * @author michael  * @see 1.5  */ public class Singleton {  //volatile 多线程共享变量  private volatile static Singleton uniqueSingleton;  //Other useful Singleton data...  /**   * 构造器私有化   */  private Singleton() {  }  /**   * @description 双检测   * @return 唯一实例   */  public static synchronized Singleton getInstance() {   if(uniqueSingleton == null) {    //多线程 可能在这堵塞 双检测 避免重复构造    synchronized(Singleton.class) {     if(uniqueSingleton == null) {      uniqueSingleton = new Singleton();      }    }   }   return uniqueSingleton;  }  //Other useful Singleton methods... } 

实现五:基于JVM对实现四的改进,避免引用还未完全初始化的对象。

解释:当第一次调用getInstance()方法,执行uniqueSingle = new Singleton()这句代码,JVM可能在new Single()并未完全执行,

就已经给uniqueSingleton 分配地址(uniqueSingleton != null),而此时如果另一个线程调用getInstance()方法,

就会得到还未完全初始化的uniqueSingleton的引用。实现五使用一个中间 变量singleton确保uniqueSingleton的完整性。

/**  * @description double checked  * @author michael  * @see since 1.5  */ public class Singleton {  //volatile 多线程共享变量  private volatile static Singleton uniqueSingleton;  //Other useful Singleton data...  /**   * 构造器私有化   */  private Singleton() {  }  /**   * @description 双检测   * @return 唯一实例   */  public static synchronized Singleton getInstance() {   if(uniqueSingleton == null) {    //多线程 可能在这堵塞 双检测 避免重复构造    synchronized(Singleton.class) {     if(uniqueSingleton == null) {      //avoid getting a reference to an incompletely initialized object      Singleton singleton = new Singleton();      uniqueSingleton = singleton;     }    }   }   return uniqueSingleton;  }  //Other useful Singleton methods... } 

效果

1.对唯一实例的受控访问

2.缩小名空间

3.允许对操作和表示的精化

4.允许可变数目的实例

5.比类操作更灵活

相关模式

很多模式可以使用单例模式实现。参见抽象工厂模式(Abstract Factory)、建造者模式(Builder),和原型模式(Prototype)。

正文到此结束
Loading...