C# 单例模式

单例模式解读:

在应用程序中,保证类型只有一个实例,只允许实例化一次;

步骤:

首先构造函数私有化,以保证对象不会被它人实例化;

提供一个公开的静态方法供他人获取对象的实例;

防止并发情况破坏单例,在创建对象时加锁

第一种方法:

    /// <summary>
    /// 懒汉式单例写法:只有在调用CreateInstance方法后才会实例化Single对象
    /// </summary>
    public sealed class Single
    {
        private Single()
        {
            long result = 0;
            for (int i = 0; i < 10000; i++)
            {
                result += i;
            }
            Thread.Sleep(1000);
            Console.WriteLine($"{this.GetType().Name}已被构造");
        }
        private static Single single = null;//静态字段在内存中是唯一的,不会被GC
        private static readonly object SingLock = new object();

        public static Single CreateInstance()
        {
            //先判断对象是否为null,不为null就不执行里面的代码,直接返回对象
            if (single == null)
            {
                //加锁:任意时刻只有一个线程能进去,解决并发问题
                lock (SingLock)
                {
                    if (single == null)//这个判断不能去掉,保证只初始化一次
                    {
                        //方法第一次进来会new一个实例,只会被构造一次
                        single = new Single();
                    }
                }
            }
            return single;
        }
        public void Message()
        {
            Console.WriteLine($"{typeof(Single)}");
        }
    }
static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                Task.Run(() =>//会抛十个线程
                {
                    Single single = Single.CreateInstance();
                    single.Message();
                });
            }
            Console.WriteLine("Hello World!");
            Console.ReadKey();
        }

第二种:

    /// <summary>
    /// 饿汉式单例写法:在调用类中的任意成员时都会先实例化这个类
    /// </summary>
    public class SingleSecond
    {
        private SingleSecond()
        {
            long result = 0;
            for (int i = 0; i < 10000; i++)
            {
                result += i;
            }
            Thread.Sleep(1000);
            Console.WriteLine($"{this.GetType().Name}以被构造");
        }
        private static SingleSecond single = null;//静态字段在内存中是唯一的,不会被GC

        /// <summary>
        /// 静态构造函数:由CLR保证,在第一次使用到这个类型之前,自动调用且只调用一次
        /// </summary>
        static SingleSecond()
        {
            single = new SingleSecond();
        }
        public static SingleSecond CreateInstance()
        {
            return single;
        }
        public void Message()
        {
            Console.WriteLine($"{typeof(SingleSecond)}");
        }
    }
static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                Task.Run(() =>//会抛十个线程
                {
                    SingleSecond single = SingleSecond.CreateInstance();
                    single.Message();
                });
            }
            Console.WriteLine("Hello World!");
            Console.ReadKey();
        }

第三种:

    /// <summary>
    /// 饿汉式单例写法:在调用类中的任意成员时都会先实例化这个类
    /// </summary>
    public class SingeThird
    {
        private SingeThird()
        {
            long result = 0;
            for (int i = 0; i < 10000; i++)
            {
                result += i;
            }
            Thread.Sleep(1000);
            Console.WriteLine($"{this.GetType().Name}以被构造");
        }
        /// <summary>
        /// 静态字段:由CLR保障,在第一次使用这个类型之前,会自动初始化且初始化一次
        /// </summary>
        private static SingeThird single = new SingeThird();
        public static SingeThird CreateInstance()
        {
            return single;
        }
        public void Message()
        {
            Console.WriteLine($"{typeof(SingleSecond)}");
        }
    }
 static void Main(string[] args)
        {
            for (int i = 0; i < 10; i++)
            {
                Task.Run(() =>//会抛十个线程
                {
                    SingeThird single = SingeThird.CreateInstance();
                    single.Message();
                });
            }
            Console.WriteLine("Hello World!");
            Console.ReadKey();
        }

单例模式的特点:

同一个实例不能解决多线程并发问题,会存在线程冲突;

全局只有一个单例,对对象里的成员进行修改时,在任何地方调用都是上次修改的值,而不是初始值;

The End!

原文地址:https://www.cnblogs.com/zhangnever/p/12402194.html