C#设计模式之【创建型设计模式:单例模式】

一.单例模式简述

  单例模式: 保证进程中,某个类只有一个实例,并提供一个访问它的全局访问点。
  优点: 单例可以避免重复创建,减少资源消耗,主要应对一些特殊情况,比如数据库连接池(内置了资源), 全局唯一号码生成器等。
  缺点: 但是使用单例模式也会常驻内存,而且它的变量不是线程安全的,除非是真的有必要,否则不要单例。来自老年人的忠告。。。

  UML图
在这里插入图片描述

二.几种实现方式

1. 非线程安全

  先写一个类

   /// <summary>
    /// 非线程安全写法
    /// </summary>
    public class Singleton1
    {

        private static Singleton1 _Singleton1 = null;

        private static int total=0;//私有变量,用于探究线程安全

        /// <summary>
        /// 构造函数
        /// </summary>
        private Singleton1()
        {
            Thread.Sleep(1000);//先休眠1秒,为了探究线程安全
            Console.WriteLine($"{this.GetType().Name}被创建");
        }

        /// <summary>
        /// 创建实例的方法
        /// </summary>
        /// <returns></returns>
        public static Singleton1 CreatesSingleton1()
        {
            if (_Singleton1 == null)
            {
                 _Singleton1 = new Singleton1();
            }

            return _Singleton1;
        }

        /// <summary>
        /// 对total做++运算
        /// </summary>
        public void AddTotal()
        {
            total++;           
        }

        /// <summary>
        /// 输出total的值
        /// </summary>
        public static void ShowTotal()
        {
            Console.WriteLine($"输出total的值为{total}");
        }
    }

  然后在控制台开辟10000个线程,同时调用CreatesSingleton1获取对象实例。看看结果如何
在这里插入图片描述
  事实证明–>这个写法不行

2. 线程安全

  为了解决线程安全问题,我们需要加锁,代码修改如下:

    /// <summary>
    /// 线程安全写法
    /// </summary>
   public class Singleton2
    {

        //volatile 促进线程安全 让线程按顺序操作
        private static volatile Singleton2 _Singleton2 = null;
        
        //用于加锁
        private static readonly object Singleton_Lock = new object();
        
        //私有变量,用于探究线程安全
        private static int total = 0;

        /// <summary>
        /// 构造函数
        /// </summary>
        private Singleton2()
        {
            Thread.Sleep(1000);//先休眠1秒,为了探究线程安全
            Console.WriteLine($"{this.GetType().Name}被创建");
        }

        /// <summary>
        /// 创建实例的方法
        /// </summary>
        /// <returns></returns>
        public static Singleton2 CreatesSingleton2()
        {
            if (_Singleton2 == null)//第一次判断,如果已有值,不需要加锁
            {
                lock (Singleton_Lock)//加锁
                {
                    if (_Singleton2 == null)//第二次判断,保证只创建一次(很关键)
                    {
                        _Singleton2 = new Singleton2();
                    }
                }            
            }
            return _Singleton2;
        }

        /// <summary>
        /// 对total做++运算
        /// </summary>
        public void AddTotal()
        {
            lock (Singleton_Lock)//加锁
            {
                total++;
            }         
        }

        /// <summary>
        /// 输出total的值
        /// </summary>
        public static void ShowTotal()
        {
            Console.WriteLine($"输出total的值为{total}");
        }
    }

在这里插入图片描述

3. 静态构造函数(饿汉式)

  为了保证单例频繁的加锁,会导致性能损耗,我们可以利用静态构造函数的特点,来实现单例模式(上面已经讨论变量的线程安全问题了,这里就不再探究。)

    /// <summary>
    /// 使用静态构造函数:由CLR保证,程序第一次使用这个类型前被调用,且只调用一次
    /// </summary>
    public class Singleton3
    {

        private static Singleton3 _Singleton3 = null;

        static Singleton3()
        {
            _Singleton3 = new Singleton3();
            Console.WriteLine($"Singleton3被构造");
        }

        public static Singleton3 CreatesSingleton3()
        {
            return _Singleton3;
        }    
    }

4. 静态字段(饿汉式)

   我们还可以使用静态字段来实现单例模式

    /// <summary>
    /// 静态字段:在第一次使用这个类之前,由CLR保证,初始化且只初始化一次
    /// </summary>
    public class Singleton4
    {

        private static Singleton4 _Singleton4 = new Singleton4();

        private Singleton4()
        {
            Console.WriteLine($"{this.GetType().Name}被构造");
        }

        public static Singleton4 CreatesSingleton4()
        {
            return _Singleton4;
        }

    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值