设计模式——单例模式

一、单例模式:保证进程中,类型只有一个实例

a) 构造函数私有化,防止他人实例化
b) 对外提供一个获取实例的途径,公开的静态方法
 c) 返回共用一个静态字段

二、为什么使用单例

  并不一定节省资源, 因为对象常驻内存,没有及时释放。
  速度会快一点,重用对象,如果每次new新对象--使用--释放,耗时。

  应用场景:

  线程池  流水号生成器   配置文件读取   IOC容器实例

  数据库连接池:数据库连接--非托管资源--申请/释放消耗性能
  池化资源--内置10个链接---使用来拿,用完放回来--避免重复申请和销毁--控制链接数量

  注意事项:单例并不能用来解决多线程并发问题。比如单例类里有一个整形字段number,如果多线程实例化这个类1000次,每次对这个字段进行++操作,即使这1000次实例化出来的对象都是同一个,但最后的结果一定是小于1000的,因为多线程对同一个资源操作,会线程冲突、线程不安全。

三、单线程写法

  

  public class Singleton
    {
        /// <summary>
        /// 私有构造函数
        /// </summary>
        private Singleton()
        {
            Console.WriteLine($"{this.GetType().Name}被构造一次");
        }

        private static Singleton _Singleton = null;
        
        public static Singleton CreateInstance()
        {
            if (_Singleton == null)
            {
                  _Singleton = new Singleton();
            }                                        
            return _Singleton;
        }
    }

 

四、多线程写法

 1、单锁(懒汉式)

 1 public class Singleton
 2     {
 3         /// <summary>
 4         /// 私有构造函数
 5         /// </summary>
 6         private Singleton()
 7         {
 8             Console.WriteLine($"{this.GetType().Name}被构造一次");
 9         }
10 
11         private static Singleton _Singleton = null;
12         private static readonly object Singleton_Lock = new object();
13         public static Singleton CreateInstance()
14         {
15             //开始多线程初始化---lock锁定--线程请求锁--开始判断创建
16            
17             lock (Singleton_Lock)//可以保证任意时刻只有一个线程进入,其他线程等待
18             {
19                 if (_Singleton == null)//这个判断不能去掉,保证只初始化一次
20                 {
21                     _Singleton = new Singleton();
22                 }
23             }
24             
25             return _Singleton;
26         }
27     }

流程:开始多线程初始化---lock锁定--线程请求锁--开始判断创建

缺点:如果以上多线程都结束后---再来多个线程请求呢?--都需要等待锁--拿到锁--进去判断--不为空--返回对象--。。。。

这样很浪费,因为此时对象已经创建了,不需要等待锁,直接判断就行了

所以有了以下双检锁方法

2、双检锁(懒汉式)

public class Singleton
    {
        /// <summary>
        /// 私有构造函数
        /// </summary>
        private Singleton()
        {
            Console.WriteLine($"{this.GetType().Name}被构造一次");
        }

        private static Singleton _Singleton = null;
        private static readonly object Singleton_Lock = new object();
        public static Singleton CreateInstance()
        {
            //开始多线程初始化---lock锁定--线程请求锁--开始判断创建
            if (_Singleton == null)
            {
                lock (Singleton_Lock)//可以保证任意时刻只有一个线程进入,其他线程等待
                {
                    if (_Singleton == null)//这个判断不能去掉,保证只初始化一次
                    {
                        _Singleton = new Singleton();
                    }
                }
            }                          
            return _Singleton;
        }
    }

 

以上两种方法因为都只有在调用CreateInstance方法时才实例化,所以称为懒汉式(饿的时候才吃)。

 

3、静态字段(饿汉式)

public class Singleton
    {
        /// <summary>
        /// 私有构造函数
        /// </summary>
        private Singleton()
        {
            Console.WriteLine($"{this.GetType().Name}被构造一次");
        }

        /// <summary>
        /// 静态字段:由CLR保障,在第一次使用这个类型之前,会自动初始化且只初始化一次
        /// </summary>
        private static Singleton _Singleton = new Singleton();      
        public static Singleton CreateInstance()
        {               
            return _Singleton;
        }
    }

静态字段:由CLR保障,在第一次使用这个类型之前,会自动初始化且只初始化一次

posted @ 2022-03-21 21:34  暗,伏!  阅读(32)  评论(0编辑  收藏  举报