首页 > 代码库 > 单例模式在多线程环境下的lazy模式为什么要加两个if(instance==null)

单例模式在多线程环境下的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,就是为了告诉别人,对象我已经创建过了!其他人就不要再创建了,不知道我这样解释,清楚不!