單例模式在多線程環境下的lazy模式為什么要加兩個if(instance==null)


剛才在看阿尋的博客”C#設計模式學習筆記-單例模式“時,發現了評論里有幾個人在問單例模式在多線程環境下為什么lazy模式要加兩個if進行判斷,評論中的一個哥們劍過不留痕,給他們寫了一個demo來告訴他們為什么。

我看了一下這個demo,確實說明了這個問題,但我認為不夠直觀,呵呵,於是我就稍微的改了一下。

這是劍過不留痕的demo

using System;
using System.Threading;
 
namespace SingletonPattern
{
    class Program
    {
        static Thread[] threads;
 
        static void Main(string[] args)
        {
            int threadsCapacity;
 
            Console.WriteLine("請輸入開啟的線程數:");
            string s;
            do
            {
                s = Console.ReadLine();
                if (!int.TryParse(s, out threadsCapacity))
                {
                    Console.WriteLine("數字格式不正確,請輸入開啟的線程數:");
                    continue;
                }
                else if (1 > threadsCapacity)
                {
                    Console.WriteLine("數字應不小於 1,請輸入開啟的線程數:");
                    continue;
                }
                else
                {
                    break;
                }
            } while (true);
 
            threads = new Thread[threadsCapacity];
            Program pg = new Program();
            for (int i = 0; i < threads.Length; i++)
            {
                Thread thread = new Thread(new ThreadStart(Singleton.GetIns));
                thread.Name = "線程 " + i;
                threads[i] = thread;
            }
 
            for (int i = 0; i < threads.Length; i++)
            {
                threads[i].Start();
            }
 
            Console.ReadKey();
        }
    }
 
    class Singleton
    {
        private static Singleton instance;
        private static object _lock = new object();
        private static int instanceQuantity = 0;
 
        private Singleton()
        {
 
        }
 
        public static Singleton GetInstance()
        {
            if (instance == null)
            {
                // 掛起線程,確保所有的線程都執行到這並等待
                Thread.Sleep(1000);
 
                lock (_lock)
                {
                    //if (instance == null)
                    //{
                    //    instance = new Singleton();
                    //    ++instanceQuantity;
                    //    Console.WriteLine(Thread.CurrentThread.Name + " 生成第 " + instanceQuantity + " 實例!");
                    //}
 
                    instance = new Singleton();
                    ++instanceQuantity;
                    Console.WriteLine(Thread.CurrentThread.Name + " 生成第 " + instanceQuantity + " 實例!");
                }
            }
            return instance;
        }
 
        public static void GetIns()
        {
            GetInstance();
        }
    }
}

 

下面是我修改過得demo,修改的地方主要在GetInstance()這個方法內部,其他地方沒動,所以我只貼出修改代碼的地方,免得占空間!

public static Singleton GetInstance()
        {
            if (instance == null)
            {
                // 掛起線程,確保所有的線程都執行到這並等待
                Console.WriteLine("我是" + Thread.CurrentThread.Name + " ,instance等於null,哦,對象還沒創建呢,看來我有機會哦!");
                Thread.Sleep(1000);

                lock (_lock)
                {
                    Console.WriteLine("我是" + Thread.CurrentThread.Name + " ,instance等於null,哈哈,我鎖,我是第一個到的!創建對象的任務就交給我了!");
                    if (instance == null)
                    {
                        instance = new Singleton();
                        ++instanceQuantity;
                        Console.WriteLine("我是" + Thread.CurrentThread.Name + " ,哼哼,對象是我創建的!");
                    }
                    else
                    {
                        Console.WriteLine("我是"+Thread.CurrentThread.Name + ",雖然我之前判斷instance等於null,但現在判斷的時候,卻不等null了,唉,還是被別人快了一步!不過好在我判斷了,要不就多創建了一個,失去了單例模式的意義!");
                    }
                    //Console.WriteLine(Thread.CurrentThread.Name + " 生成第 " + instanceQuantity + " 實例!");
                    //instance = new Singleton();
                    //++instanceQuantity;
                    //Console.WriteLine(Thread.CurrentThread.Name + " 生成第 " + instanceQuantity + " 實例!");
                }
            }
            return instance;
        }

 

下面是運行的結果,多運行幾遍就可能出現這個結果了。

文字描述:

雖然線程0先進的第一個if,但創建對象的確實線程1,而此時,線程0已經判斷了instance==null,所以他還會再創建一個對象,因為並沒有人告訴線程0,線程1已經創建過對象了,而內部的這個if,就是為了告訴別人,對象我已經創建過了!其他人就不要再創建了,不知道我這樣解釋,清楚不!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM