色婷婷AV无码久久精品,久久天天躁狠狠躁夜夜97,羞羞麻豆国产精品1区2区3区,啪影院免费线观看视频,思思久久er99精品亚洲

常州機(jī)器視覺培訓(xùn)

常州上位機(jī)軟件開發(fā)

常州工業(yè)機(jī)器人編程設(shè)計(jì)培訓(xùn)

常州PLC培訓(xùn)

常州PLC

常州PLC編程培訓(xùn)

常州電工培訓(xùn)

常州和訊plc培訓(xùn)中心歡迎您!
當(dāng)前位置:網(wǎng)站首頁 > 新聞中心 新聞中心
淺談單例模式-常州機(jī)器視覺培訓(xùn),常州上位機(jī)培訓(xùn)
日期:2024-2-1 16:30:57人氣:  標(biāo)簽:常州機(jī)器視覺培訓(xùn) 常州上位機(jī)培訓(xùn)

前言

什么是單例模式?

單例模式,屬于創(chuàng)建類型的一種常用的軟件設(shè)計(jì)模式。通過單例模式的方法創(chuàng)建的類在當(dāng)前進(jìn)程中只有一個實(shí)例(根據(jù)需要,也有可能一個線程中屬于單例,如:僅線程上下文內(nèi)使用同一個實(shí)例)

上面是百度百科給出的解釋。

大家都知道,面向?qū)ο蟮乃枷刖褪俏覀兛梢园岩粋類實(shí)例很多次,每次實(shí)例出來的都是一個對象,意味著你可以創(chuàng)建很多個基于這個類的對象。

單例模式,說白了,就是這些對象本質(zhì)都是同一個,整個程序中,不管在哪里用,使用的都是同一個實(shí)例對象。

如果我們創(chuàng)建了一個China類,我們可以一直new嗎?不可以,因?yàn)槭澜缟现挥幸粋China,所以我們使用的都是同一個China對象。

Version 1 - 非線程安全

    public class China

    {

        private China()

        {

        }

        private static China china = null;


        public static China Instance

        {

            get

            {

                if (china == null)

                {

                    Console.WriteLine("實(shí)例化對象");

                    china = new China();

                }

                return china;

            }

        }

    }

最簡單的實(shí)現(xiàn)方式如上圖,創(chuàng)建一個私有的靜態(tài)對象和私有構(gòu)造方法,然后在CreateInstance方法里,加一個判斷,如果為Null,就重新實(shí)例化一下,否則直接返回。

這種寫法從邏輯上是沒問題的,但是是否會出現(xiàn)這個if (china == null)判斷,同時執(zhí)行,這樣就麻煩了。

所以這種寫法在單線程的程序是沒問題的,但是在多線程中,是可能會有問題的。

我們做個測試,測試代碼如下:


    class Program

    {

        static void Main(string[] args)

        {

            for (int i = 0; i < 10; i++)

            {

                new TaskFactory().StartNew(() =>

                {

                    China china =  China.Instance;

                });

                Thread.Sleep(10);

            }

            Console.ReadLine();

        }

    }

上面的代碼,就是創(chuàng)建10個線程,都執(zhí)行CreatInstance方法,那么最終是輸出多少次Console.WriteLine("實(shí)例化對象")呢?

18.png

19.png

我們測試發(fā)現(xiàn),這個輸出結(jié)果是不唯一的,有時候會輸出5次,有時候會輸出2次,但是一般都是超過1次,這個就說明對象被多次實(shí)例化了,這就違背了單例模式的原則。


Version 2 - 簡單的線程安全

既然出現(xiàn)問題,那么我們就需要做一下優(yōu)化,優(yōu)化之后的代碼如下:


    public class China

    {

        private China()

        {

        }

        private static China china = null;


        private static object objlock = new object();

        public static China Instance

        {

            get

            {

                lock (objlock)

                {

                    Console.WriteLine("執(zhí)行判斷");

                    if (china == null)

                    {

                        Console.WriteLine("實(shí)例化對象");

                        china = new China();

                    }

                }

                return china;

            }

        }

    }

對比看下,就是加了一個同步鎖,這樣就可以避免同時執(zhí)行的情況,并且,我們在lock里加了一個Console.WriteLine("執(zhí)行判斷"),觀察這行代碼執(zhí)行多少次。

20.png

從結(jié)果來看,實(shí)例化對象只執(zhí)行了一次,說明對象只被創(chuàng)建過一次,滿足了我們的需求,達(dá)到了預(yù)期的效果。


Version 3 - 雙if+lock實(shí)現(xiàn)

上面那種方式已經(jīng)可以達(dá)到預(yù)期效果,但是我們注意到一個問題,執(zhí)行判斷這行代碼被執(zhí)行了10次,這顯示不符合我們的邏輯,既然已經(jīng)實(shí)例化了,為什么每次還要執(zhí)行判斷呢?是不是多此一舉?并且每次請求對象,都會進(jìn)行l(wèi)ock操作,lock對性能是有一定影響的。


于是我們繼續(xù)優(yōu)化,優(yōu)化之后的代碼如下:


    public class China

    {

        private China()

        {

        }

        private static China china = null;


        private static object objlock = new object();

        public static China Instance

        {

            get

            {

                if (china == null)

                {

                    lock (objlock)

                    {

                        Console.WriteLine("執(zhí)行判斷");

                        if (china == null)

                        {

                            Console.WriteLine("實(shí)例化對象");

                            china = new China();

                        }

                    }

                }

                return china;

            }

        }

    }

我們對比代碼可以看出,就是又加了一個if (china == null),這種雙if+lock的方式,是不是可以解決我們的問題呢?


我們執(zhí)行一次,看看結(jié)果:

21.png

我們通過結(jié)果可以看到只執(zhí)行了一次判斷,也只執(zhí)行一次實(shí)例化對象,但是我們還可以繼續(xù)優(yōu)化。


Version 4 - 靜態(tài)變量實(shí)現(xiàn)

話不多說,直接上代碼:


    public class China

    {

        private China()

        {

        }

        private static readonly China china = new China();

        public static China Instance

        {

            get

            {

                return china;

            }

        }

    }

利用靜態(tài)變量去實(shí)現(xiàn)單例,非常簡單,但同時也是線程安全的,由CLR保證,在程序第一次使用該類之前被調(diào)用,而且只調(diào)用一次。


但是這種方式也有缺點(diǎn),就是實(shí)例化過程是在程序初始化時就執(zhí)行的,而不是在使用時才執(zhí)行,就是說,不管你用不用,都已經(jīng)實(shí)例化了。


Version 5 - 完全懶漢式實(shí)現(xiàn)

    public class China

    {

        private China()

        {

        }

        public static China Instance

        {

            get

            {

                return Lazy.instance;

            }

        }

        private class Lazy

        {

            static Lazy()

            {

            }

            internal static readonly China instance = new China();

        }

    }

這種方法與上一種方法類似,只是多加了一個類,來解決上一個版本的缺點(diǎn)。


Version 6 - 使用Lazy特性

從.NET 4開始,可以使用Lazytype來實(shí)現(xiàn)完全懶漢式,代碼也變得更簡單,代碼如下:


    public class China

    {

        private China()

        {

        }

        private static readonly Lazy<China> lazy = new Lazy<China>(() => new China());

        public static China Instance

        {

            get

            {

                return lazy.Value;

            }

        }

    }

整體總結(jié)

可能大家看完之后,選擇困難癥又會犯了吧?


這里給大家總結(jié)一下,除了Version 1,其他幾種情況,均可以實(shí)現(xiàn)單例模式,一般情況下我們使用Vesion 2和Version 4比較多,雖然Version 2會浪費(fèi)一定的資源,但是很容易理解,實(shí)際應(yīng)用中,影響不會很大。

本文網(wǎng)址:
下一篇:沒有資料

相關(guān)信息:
版權(quán)所有 CopyRight 2006-2017 江蘇和訊自動化設(shè)備有限公司 常州自動化培訓(xùn)中心 電話:0519-85602926 地址:常州市新北區(qū)府琛商務(wù)廣場2號樓1409室
蘇ICP備14016686號-2 技術(shù)支持:常州山水網(wǎng)絡(luò)
本站關(guān)鍵詞:常州PLC培訓(xùn) 常州PLC編程培訓(xùn) 常州PLC編程 常州PLC培訓(xùn)班 網(wǎng)站地圖 網(wǎng)站標(biāo)簽
在線與我們?nèi)〉寐?lián)系
色婷婷AV无码久久精品,久久天天躁狠狠躁夜夜97,羞羞麻豆国产精品1区2区3区,啪影院免费线观看视频,思思久久er99精品亚洲