Singleton

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

要做到单例,必须要解决一下几个问题:

1 怎么保证呢?怎么样强制保证呢?

单例模式的三部曲:A.构造方法私有化,防止外部对它实例化。B. 静态对象、方法的申明。C.判断对象是否为空,为空则创建对象,最后返回对象。

示例代码:

 

 1 /// <summary>
 2     /// 单例类:一个构造对象很耗时耗资源类型
 3     /// 懒汉式单例模式
 4     /// </summary>
 5     public class Singleton
 6     {
 7         /// <summary>
 8         /// 构造函数耗时耗资源
 9         /// </summary>
10         private Singleton()
11         {
12             18             Console.WriteLine("{0}被构造一次", this.GetType().Name);
19         }
20         /// <summary>
21         /// 3 全局唯一静态  重用这个变量
22         /// </summary>
23         private static volatile Singleton _Singleton = null;
24         //volatile 促进线程安全 让线程按顺序操作
25         private static readonly object Singleton_Lock = new object();
26         /// <summary>
27         /// 2 公开的静态方法提供对象实例
28         /// </summary>
29         /// <returns></returns>
30         public static Singleton CreateInstance()
31         {
40             if (_Singleton == null)//保证只实例化一次
41            {
42             _Singleton = new Singleton();
43            }46             return _Singleton;
47         }
65     }

调用:Console.WriteLine(object.ReferenceEquals(singleton1, singleton2));  控制台输出ture,则说明这个两个对象是同一个对象。

 1  static void Main(string[] args)
 2         {
 3             try
 4             {
 5                 //为什么要有单例设计模式?
 6                 //构造对象耗时耗资源,很多地方都需要去new, 这个方法 其他方法  其他类
 7                 //想避免重复构造,公开静态字段 
 8                 //1 提前构造  2 没办法保证都是用这个(其他人还是new了一下) 
 9                 //Singleton singleton = new Singleton();
10                 //singleton.Show();
11 
12                 //{
13                 //    ////保证进程中,某个类只有一个实例
14                 //    ////1 构造函数私有化 避免别人还去new
15                 //    ////2 公开的静态方法提供对象实例
16                 //    ////3 初始化一个静态字段用于返回 保证全局都是这一个
17                  Singleton singleton1 = Singleton.CreateInstance();
18                  Singleton singleton2 = Singleton.CreateInstance();
19                  Singleton singleton3 = Singleton.CreateInstance();
20                       Console.WriteLine(object.ReferenceEquals(singleton1, singleton2));
21                       Console.WriteLine(object.ReferenceEquals(singleton3, singleton2));
22                  }
23             catch (Exception ex)
24             {
25                 Console.WriteLine(ex.Message);
26             }
27             Console.Read();
28         }

多线程调用:控制台输出 对象被构造了五次,这时候就会发现结果和我们预期的不一样了。

{
       for (int i = 0; i < 5; i++)
       {
          Task.Run(() =>//启动线程完成--5个线程并发执行,同时去执行这个方法
           {
            Singleton singleton1 = Singleton.CreateInstance();
             singleton1.Show();
           });
} }

对上述单例模式进行改造,要求是满足多线程使用场景、单线程使用场景。

 1 /// <summary>
 2     /// 单例类:一个构造对象很耗时耗资源类型
 3     /// 懒汉式单例模式
 4     /// </summary>
 5     public class Singleton
 6     {
 7         /// <summary>
 8         /// 构造函数耗时耗资源
 9         /// </summary>
10         private Singleton()
11         {
12             long lResult = 0;
13             for (int i = 0; i < 10000000; i++)
14             {
15                 lResult += i;
16             }
17             Thread.Sleep(2000);
18             Console.WriteLine("{0}被构造一次", this.GetType().Name);
19         }
20         /// <summary>
21         /// 3 全局唯一静态  重用这个变量
22         /// </summary>
23         private static volatile Singleton _Singleton = null;
24         //volatile 促进线程安全 让线程按顺序操作
25         private static readonly object Singleton_Lock = new object();
26         /// <summary>
27         /// 2 公开的静态方法提供对象实例
28         /// </summary>
29         /// <returns></returns>
30         public static Singleton CreateInstance()
31         {
32             if (_Singleton == null)//是_Singleton已经被初始化之后,就不要进入锁等待了
33             {
34                 lock (Singleton_Lock)
35                 //保证任意时刻只有一个线程进入lock范围
36                 //也限制了并发,尤其是_Singleton已经被初始化之后
37                 {
38                     //Thread.Sleep(1000);
39                     //Console.WriteLine("等待锁1s之后才继续。。。");
40                     if (_Singleton == null)//保证只实例化一次
41                     {
42                         _Singleton = new Singleton();
43                     }
44                 }
45             }
46             return _Singleton;
47         }
48 
49         //既然是单例,大家用的是同一个对象,用的是同一个方法,那还会并发吗  还有线程安全问题吗?
50         public int iTotal = 0;
51         public void Show()
52         {
53             //lock (Singleton_Lock)
54             //{
55                 this.iTotal++;
56             //}
57         }
58 
59         public static void Test()
60         {
61             Console.WriteLine("Test1");
62             Console.WriteLine(_Singleton.iTotal);
63         }
64 
65     }

多线程调用: 

 Thread.Sleep(10000);
  Console.WriteLine("第一波多线程后,再度来请求实例");
     for (int i = 0; i < 5; i++)
     {
           Task.Run(() =>//启动线程完成--5个线程并发执行,同时去执行这个方法
           {
               Singleton singleton1 = Singleton.CreateInstance();
               singleton1.Show();
            });
     }

注意:多线程中单例的使用 最主要的是 双重if判断,和加锁。内层if判断的作用是第一次调用实例化一次,下次在调用的时候不用实例化对象。加锁的作用说保证线程安全(加锁后就变成的单线程,第一个线程没有处理完,后面的线程都需要等待,这个时候就使用多线程就失去了意义),为了解决加锁后编程单线程问题,所以在锁外面在加一层If判断,多线程操作程序会并发执行,当第一个线程已经创建了对象 ,其他线程进入方法是检测到对象已经不为空后,直接返回对象。这样就不用等待,提高了程序的效率。

饿汉式单例

  

 1 /// <summary>
 2     /// 单例类:一个构造对象很耗时耗资源类型
 3     /// 
 4     /// 饿汉式
 5     /// </summary>
 6     public class SingletonSecond
 7     {
 8         /// <summary>
 9         /// 1 构造函数耗时耗资源
10         /// </summary>
11         private SingletonSecond()
12         {
13             long lResult = 0;
14             for (int i = 0; i < 10000000; i++)
15             {
16                 lResult += i;
17             }
18             Thread.Sleep(1000);
19             Console.WriteLine("{0}被构造一次", this.GetType().Name);
20         }
21         /// <summary>
22         /// 静态构造函数:由CLR保证,程序第一次使用这个类型前被调用,且只调用一次
23         /// 
24         /// 检测,初始化
25         /// 写日志功能的文件夹检测
26         /// XML配置文件
27         /// </summary>
28         static SingletonSecond()
29         {
30             _SingletonSecond = new SingletonSecond();
31             Console.WriteLine("SingletonSecond 被启动");
32         }
33 
34 
35         private static SingletonSecond _SingletonSecond = null;
36         public static SingletonSecond CreateInstance()
37         {
38             return _SingletonSecond;
39         }//饿汉式  只要使用类就会被构造
40 
41         /// <summary>
42         /// 原型模式:解决对象重复创建的问题
43         /// 通过MemberwiseClone来clone新对象,内存操作,直接复制的,避免重复创建
44         /// </summary>
45         /// <returns></returns>
46         public static SingletonSecond CreateInstancePrototype()
47         {
48             SingletonSecond second = (SingletonSecond)_SingletonSecond.MemberwiseClone();
49             return second;
50         }
51 
52         public static void Test()
53         {
54             Console.WriteLine("Test2");
55         }
56 
57 
58 
59         public int iTotal = 0;
60         public void Show()
61         {
62             this.iTotal++;
63         }
64 
65     }

第三种单例模式 :

 1 /// <summary>
 2     /// 单例类:一个构造对象很耗时耗资源类型
 3     /// 饿汉式
 4     /// </summary>
 5     public class SingletonThird
 6     {
 7         /// <summary>
 8         /// 构造函数耗时耗资源
 9         /// </summary>
10         private SingletonThird()
11         {
12             long lResult = 0;
13             for (int i = 0; i < 10000000; i++)
14             {
15                 lResult += i;
16             }
17             Thread.Sleep(1000);
18             Console.WriteLine("{0}被构造一次", this.GetType().Name);
19         }
20 
21         /// <summary>
22         /// 静态字段:在第一次使用这个类之前,由CLR保证,初始化且只初始化一次
23         /// 这个比今天构造函数还早
24         /// </summary>
25         private static SingletonThird _SingletonThird = new SingletonThird();//打印个日志
26         public static SingletonThird CreateInstance()
27         {
28             return _SingletonThird;
29         }//饿汉式  只要使用类就会被构造

34 public void Show() 35 { 36 Console.WriteLine("这里是{0}.Show", this.GetType().Name); 37 } 38 39 }

 

辅导费

 

posted @ 2019-01-23 13:59  小小竹  阅读(238)  评论(0编辑  收藏  举报