Singleton模式的实现

1.实现Singleton模式

设计一个类,我们只能生成该类的一个实例。

2.低级解法一:只适用于单线程环境

因为我们只能生成一个实例,所以我们必须把构造函数设置为私有函数已禁止他人创建实例。可以定义一个静态的实例,在需要的时候创建该实例。

 
 
public sealed class Sinleton1
{
    private Singleton1() {}
    private static Singleton1 instance = null;
    public static Singleton1 instance
    {
      get
      {
        if(instance == null)
          instance = new Singleton1();

          return instance;
      }
    }
}

代码中,Singleton的静态属性Instance中,只有在instance为null的时候才会创建一个实例避免重复创建。同时我们吧构造函数定义为私有函数,这样就能确保只创建一个实例。

3.低级解法二:虽然在多线程环境中能运行但是效率低下

2中的代码在单线程中是可以工作的,但是再多线程的情况下就会出现问题。假如两个线程同时运行到判断 instance==null语句时,并且这个时候instance确实没有被创建,那么两个线程都会创建一个instance,此时类型Singleton就不满足单例模式的要求了。为了保证多线程条件下,我们仍能只得到类型的一个实例,需要加上一个同步锁。代码如下:

public sealed class Singleton2
{
    private Singleton2() {}
    
    private static readonly object syncObj = new object();
    private  static Singleton2 instance = null;
    public static Singleton2 Instance
    {
      get
      {
        lock(syncObj)
        {
          if(instance == null)
            instance = new Singleton2();
        }
        return instance;
      }
    }
}

由于一个时刻只有一个线程能得到同步锁,当第一个线程加上琐事,第二个线程只能等待。当地一个线程发现实例还没有创建时,他会创建一个实例。接着第一个线程释放同步锁,此时第二个线程可以加上同步锁,并运行接下来的代码。这个时候由于实例已经被第一个线程创建出来了,第二个线程就不会创建实例了。这就保证了我们在多线程换金钟只能得到一个实例。

然而我们不得不接受这样的一个现实,每次通过属性Instance得到Singleton2的实例,都会试图加上一个同步锁,而加锁是一个非常耗时的操作,在没有必要的时候应该避免。

4.高级解法一:嵌套类

public sealed class Singleton3
{
    Singleton3() {}
    public static Singleton3 Instance
    {
      get
      {
        return Nested.instance;
      }
    }
    
    class Nested
    {
      static Nested() {}
      internal static readonly Singleton3 instance = new Singleton3();
    }
}
内部定义了一个私有类型Nested,当第一次用到这个嵌套类型的时候,就会调用静态构造函数Singleton3的实例instance。类型Nested只在属性Singleton3.instance中被用到,由于它是私有的,其他人无法使用Nested类型。因此,当我们第一次试图通过属性Singleton3Instance得到Singleton3的实例时,会自动调用Nested的静态构造函数创建实例instance。

猜你喜欢

转载自blog.csdn.net/shenziheng1/article/details/80194007