C#設計模式之單例模式

    最近常常會看一些設計模式上書籍,對設計模式有了必定的瞭解,特此作一下筆記,也給博友們提供一些幫助。數據庫

1.什麼是單例模式?設計模式

     網上有不少文章都有詳情的描述,大體意思上能夠理解爲一個類只有一個實例,也就是保證一個類只有一種實例的實現方法,官方上是這樣定義的:確保一個類只有一個實例,並提供一個全局訪問點。多線程

通俗易懂就是:每次去實例化一個對象都是同一個,指向的都是同一個內存地址。併發

2.爲何要使用單例模式,單例模式的好處在哪?性能

      每一種設計模式均可以解決開發中遇到的一些問題,好比說提升性能,解耦合,可擴展,功能更加靈活等等。測試

      現實中的應用場景: 咱們平常使用的電腦上都有一個回收站,在整個操做系統中,回收站只能有一個實例,整個系統都使用這個惟一的實例,並且回收站自行提供本身的實例。所以回收站是單例模式的應用。平常開發中遇到與數據庫創建鏈接,若是每次都是建立新對象去創建鏈接,速度回很慢,因此設計成單例模式,提升訪問速度。優化

3.單例模式在C#中的具體實現。this

    確保一個類只有一個實例,並提供一個全局訪問點。咱們依照這個思路進行實現。spa

    本次單例實現總共用了三種方式進行簡單實現:操作系統

    方式一:

    

 /// <summary>
    /// 單例模式的簡單實現
    /// </summary>
    public class Singleton
    {
        /// <summary>
        /// 建立全局靜態變量
        /// </summary>
        private static Singleton _singleton = null;
        /// <summary>
        /// 私有化默認構造器,爲何要私有化默認構造器,若是不私有,那麼能夠經過new Singleton()進行實例化對象了,就達不到預想效果。
        /// </summary>
        private Singleton()
        {

        }
        /// <summary>
        /// 提供一個建立實例的方法
        /// </summary>
        /// <returns></returns>
        public static Singleton CreatInstance()
        {
            //判斷,若是對象沒有建立,那麼進行建立。有建立,不在重複建立
            if (_singleton == null)
            {
                _singleton=new Singleton();
            }
            return _singleton;
        }
    }

 

  測試結果以下:

     看測試結果確實達到了咱們預想的要求。單例的效果已經達到了,可是並非很完美,當前只在單線程上是知足了,若是多線程下又是怎麼樣的呢?接下來就用一個簡單的例子測試一下多線程的使用的狀況下。代碼實現以下:

 //多線程模擬,十個線程同時訪問
            for (int i = 0; i < 10; i++)
            {
                new Action(() =>
                {
                    Thread.Sleep(1000);
                    Singleton singleton = Singleton.CreatInstance();
                    singleton.Show(); //在Singleton類裏面添加一個無參的Show方法

                }).BeginInvoke(null, null);
            }

  

   

  如上圖發現,當十個線程同時訪問時,建立了多個對象的實例,並沒達到單例模式的效果。爲何會這樣?緣由是這樣的,當第一個線程進入後,

            //判斷,若是對象沒有建立,那麼進行建立。有建立,不在重複建立
            if (_singleton == null)
            {
                _singleton=new Singleton();
            }

 會去判斷這個對象是否已經被實例化,由於程序執行速度是很快的,當第一個線程發現對象未實例化時,第一個線程開始對對象進行實例化,第一個線程還未實例化完成第二個線程就已經進來了,開始對對象進行判斷,開始實例化。最終形成如上效果。

    針對如上狀況,怎麼解決呢?有人就會想到,加把鎖鎖起來就好了。這種想法很是正確。咱們看看加鎖後實現的方式。

 

 public class Singleton
    {
        /// <summary>
        /// 建立全局靜態變量
        /// </summary>
        private static Singleton _singleton = null;
        private static object singleton_lock=new object();
        /// <summary>
        /// 私有化默認構造器
        /// </summary>
        private Singleton()
        {
            Console.WriteLine("建立了Singleton對象的實例");
        }
        /// <summary>
        /// 提供一個建立實例的方法
        /// </summary>
        /// <returns></returns>
        public static Singleton CreatInstance()
        {
            lock (singleton_lock)
            {
                //判斷,若是對象沒有建立,那麼進行建立。有建立,再也不重複建立
                if (_singleton == null)
                {
                    _singleton = new Singleton();
                }
            }
            return _singleton;
        }
        public void Show()
        {
            Console.WriteLine($"執行Show方法:{this.GetType()}");
        }
    }

  運行後以下圖:

多線程同時訪問的狀況下的問題就已經解決了。固然還能夠再次優化一下,爲了看到效果,對代碼進行以下改造

改造以後再次執行

如上圖發現,每個線程都進入lock裏面,若是第一個線程進入lock實例化了對象,那麼第二個就能夠沒有必要進入lock,咱們能夠在線程進入lock前進行判斷,最終代碼改造以下,

 /// <summary>
    /// 單例模式的簡單實現
    /// </summary>
    public class Singleton
    {
        /// <summary>
        /// 建立全局靜態變量
        /// </summary>
        private static Singleton _singleton = null;
        private static object singleton_lock=new object();
        /// <summary>
        /// 私有化默認構造器
        /// </summary>
        private Singleton()
        {
            Console.WriteLine("建立了Singleton對象的實例");
        }
        /// <summary>
        /// 提供一個建立實例的方法
        /// </summary>
        /// <returns></returns>
        public static Singleton CreatInstance()
        {
            if (_singleton == null)
            {
                lock (singleton_lock)
                {
                    Console.WriteLine("開始進入lock...");
                    //判斷,若是對象沒有建立,那麼進行建立。有建立,不在重複建立
                    if (_singleton == null)
                    {
                        _singleton = new Singleton();
                    }
                }
            }
            return _singleton;
        }
        public void Show()
        {
            Console.WriteLine($"執行Show方法:{this.GetType()}");
        }
    }

  執行效果以下

圖中發現線程進入lock的次數少了,線程併發少可能做用不大,若是是併發量達到百萬次甚至更多,那麼效率會有明顯提高。雙if加lock是最標準的實現單例模式的寫法。

接下來介紹兩種比較簡便的單例模式的實現,效果和上面的同樣。

方式2、

 public class SingletonSecond
    {
        private static SingletonSecond _singletonSecond = new SingletonSecond();
        private SingletonSecond()
        {
            Console.WriteLine("建立了該對象的實例");
        }

        public static SingletonSecond CreatInstance()
        {
            return _singletonSecond;
        }
        public void Show()
        {
            Console.WriteLine($"執行Show方法:{this.GetType()}");
        }
    }

  

方式3、

 public class SingletonThrird
    {
        private static SingletonThrird _singletonThrid = null;
        private SingletonThrird()
        {
            Console.WriteLine("建立了該對象的實例");
        }
        static SingletonThrird()
        {
            _singletonThrid=new SingletonThrird();
        }
        public static SingletonThrird CreatInstance()
        {
            return _singletonThrid;
        }
        public void Show()
        {
            Console.WriteLine($"執行Show方法:{this.GetType()}");
        }
    }

  

以上就單例模式的實現方式。提供參考,職場小白歡迎指正!

相關文章
相關標籤/搜索