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

 

posted @ 2014-06-19 23:44  Geodon  阅读(2632)  评论(8编辑  收藏  举报