设计模式--单例模式

来源:互联网 发布:建造者模式知乎 编辑:程序博客网 时间:2024/06/11 01:33

单例模式(Singleton Pattern)
定义:确保一个类有且仅有一个实例,而且自行实例化并向整个系统提供这个实例
类型:创建型模式
单例的几种实现方式
原始的单例模式的构造方式

复制代码
public class Singleton {  //静态实例  private static Singleton singleton;  //私有化构造函数  private Singleton() {}  //公共静态方法返回单一实例  public static Singleton getInstance(){    if(singleton == null){      singleton = new Singleton();    }    return singleton;  }}
复制代码

这是在不考虑并发访问时情况下标准的单例模式的构造方式,而在并发情况下非线程安全。
这里提供几种解决方案:
第一、使用synchronized来处理,即将getInstance()方法变成同步方法

复制代码
public class Singleton {  //静态实例  private static Singleton singleton;  //私有化构造函数  private Singleton() {}  //公共静态方法返回单一实例  public synchronized static Singleton getInstance(){    if(singleton == null){      singleton = new Singleton();    }    return singleton;  }}
复制代码

  上面的做法很简单,就是将整个获取实例的方法同步,这样在一个线程访问这个方法时,其它所有的线程都要处于挂起等待状态,这样虽然避免了同步访问创造出多个实例的可能,但这样会造成很多无谓的等待。
  其实同步的地方只是需要发生在单例的实例还未创建的时候,在实例创建以后,获取实例的方法就没必要再进行同步控制了,所以我们将上面的示例做进一步改进,也称为双重加锁
第二、用双重检查加锁,在getInstance()中减少使用同步

复制代码
public class Singleton {  //静态实例  private static Singleton singleton;  //私有化构造函数  private Singleton(){}  //公共静态方法返回单一实例  public static Singleton getInstance(){    if (singleton == null) {      synchronized (Singleton.class) {        if (singleton == null) {          singleton = new Singleton();        }      }    }    return singleton;  }}
复制代码

  这种做法与相比第一种要好很多,因为我们只是在当前实例为null,也就是实例还未创建时才进行同步,否则就直接返回,这样就节省了很多无谓的线程等待时间,值得注意的是在同步块中,我们再次判断了singleton是否为null,解释下为什么要这样做。
假设我们去掉同步块中的是否为null的判断,有这样一种情况,假设A线程和B线程都在同步块外面判断了singletonnull,结果A线程首先获得了线程锁,进入了同步块,然后A线程会创造一个实例,此时singleton已经被赋予了实例,A线程退出同步块,直接返回了第一个创造的实例,此时B线程获得线程锁,也进入同步块,此时A线程其实已经创造好了实例,B线程正常情况应该直接返回的,但是因为同步块里没有判断是否为null,直接就是一条创建实例的语句,所以B线程也会创造一个实例返回,此时就造成创造了多个实例的情况。
  经过分析,上述双重加锁的示例看起来是没有问题了,但如果深入到JVM中去探索上面这段代码,它就有可能(注意,只是有可能)是有问题的。因为虚拟机在执行创建实例的这一步操作的时候,其实是分了好几步去进行的,也就是说创建一个新的对象并非是原子性操作。在有些JVM中上述做法是没有问题的,但是有些情况下是会造成莫名的错误。所以我们在语言级别无法完全避免错误的发生,我们只有将该任务交给JVM,因此有了第三种单例实现方式。
第三、使用静态的内部类作为单例

复制代码
public class Singleton {  //私有化构造函数  private Singleton(){}  //公共静态方法返回单一实例  public static Singleton getInstance(){    return SingletonInstance.instance;  }  private static class SingletonInstance{    static Singleton instance = new Singleton();  }}
复制代码
0 0
原创粉丝点击