1. 程式人生 > 其它 >單例模式:程序唯一。

單例模式:程序唯一。

單例模式:程序唯一。

  • 非執行緒安全。

    public sealed class SingletonV1
    {
        private static SingletonV1 instance = null;
    
        private SingletonV1()
        {
        }
    
        public static SingletonV1 Instance
        {
            get
            {
                if (instance == null) // -> 1
                { // -> 2
                    instance = new SingletonV1();
                }
    
                return instance;
            }
        }
    }
    

    假設:首次訪問,同一時間,有N(N>=2)個執行緒同時訪問單例。

    解:

    1. 例項並未建立,所有執行緒都能進入建立例項程式碼塊。
    2. N個執行緒使用的例項不相同。

    注:違反了單例的唯一性原則。

  • 簡單執行緒安全。

    public sealed class SingletonV2
    {
        private static SingletonV2 instance = null;
        private static readonly object padlock = new object();
    
        SingletonV2()
        {
        }
    
        public static SingletonV2 Instance
        {
            get
            {
                lock (padlock) // -> 1
                {
                    if (instance == null)
                    {
                        instance = new SingletonV2();
                    }
                    return instance;
                }
            }
        }
    }
    

    假設:同一時間,有N(N>=2)個執行緒同時訪問單例。

    解:由於lock是悲觀鎖,導致獲取單例變成了單執行緒操作。

    注:單執行緒的程式碼塊,會嚴重降低多執行緒的效能。

  • 雙重檢查執行緒安全。

    public sealed class SingletonV3
    {
        private static SingletonV3 instance = null;
        private static readonly object padlock = new object();
    
        SingletonV3()
        {
        }
    
        public static SingletonV3 Instance
        {
            get
            {
                if (instance == null) // -> 1
                {
                    lock (padlock)
                    {
                        if (instance == null) // -> 2
                        {
                            instance = new SingletonV3();
                        }
                    }
                }
                return instance;
            }
        }
    }
    

    解:

    1. 第一層檢查的意義:當例項被建立後,不再進入鎖。
    2. 第二層檢查的意義:併發時,可能有多個執行緒躲過了第一層檢查,在鎖內部判斷,確保僅有一個執行緒建立例項。

    注:只有例項未被建立之前的呼叫是單執行緒。

  • 非懶惰執行緒安全。

    public sealed class SingletonV4
    {
        private static readonly SingletonV4 instance = new SingletonV4(); // -> 1
    
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static SingletonV4()
        {
        }
    
        private SingletonV4()
        {
        }
    
        public static SingletonV4 Instance
        {
            get
            {
                return instance;
            }
        }
    }
    

    解:單例會在首次觸發靜態屬性/方法時,生成例項。

    注:若類中存在靜態屬性/方法時,呼叫靜態屬性/方法也會建立例項,導致單例提前工作。

  • 推薦完全懶惰執行緒安全。

    public sealed class SingletonV5
    {
        private SingletonV5()
        {
        }
    
        public static SingletonV5 Instance { get { return Nested.instance; } } // -> 1
    
        private class Nested
        {
            // Explicit static constructor to tell C# compiler
            // not to mark type as beforefieldinit
            static Nested()
            {
            }
    
            internal static readonly SingletonV5 instance = new SingletonV5(); 
        }
    }
    

    注:僅在首次使用【SingletonV5.Instance】時,會建立例項。

  • 懶載入執行緒安全。

    public sealed class SingletonV6
    {
        private static readonly Lazy<SingletonV6> lazy =
            new Lazy<SingletonV6>(() => new SingletonV6());
    
        public static SingletonV6 Instance { get { return lazy.Value; } }
    
        private SingletonV6()
        {
        }
    }
    

    注:使用懶載入,保證所有執行緒使用的例項相同,但並一定只會初始化一次例項。

    引用:

  • 強力推薦完全懶惰執行緒安全--反射。

    public class SingletonV7<T> where T : class
    {
        static SingletonV7() { }
    
        public static T Instance => Nested.Instance;
    
        private static class Nested
        {
            static Nested() { }
    
            public static readonly T Instance = (T)Activator.CreateInstance(typeof(T), true); // -> 1
        }
    }
    

    解:

    1. 作為基類。

      定義:繼承SingletonV7<T>,其中T是需要作為單例的類。

      public sealed class Singleton : SingletonV7<Singleton>
      {
          private Singleton() { }
          
          public int Add(int i, int j) => i + j;
      }
      

      用法:

      int value = Singleton.Instance.Add(1, 2);
      
    2. 作為工具類。

      定義:任意包含(公共/私有)無參建構函式的類。

      public sealed class Singleton
      {
          private Singleton() { }
          
          public int Add(int i, int j) => i + j;
      }
      

      用法:

      int value = Singleton.Instance.Add(1, 2);
      
願好運如影隨形!