码迷,mamicode.com
首页 > 其他好文 > 详细

设计模式之单例模式

时间:2016-08-30 01:51:11      阅读:240      评论:0      收藏:0      [点我收藏+]

标签:

1.前言
很多时候,我们需要为某个类型创建独一无二的对象。比如系统配置文件、工具类、线程池、缓存、系统日志等,此时单例模式应运而生。   
                单例模式: 确保一个类只有一个实例,并提供一个全局访问点
举例1
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Text;
 4 
 5 namespace 单例模式
 6 {
 7    public class Program
 8     {
 9         static void Main(string[] args)
10         {
11             Singleton s1 = Singleton.GetInstance();
12             Singleton s2 = Singleton.GetInstance();
13 
14             if (s1 == s2)
15             {
16                 Console.WriteLine("Objects are the same instance");
17             }
18 
19             Console.Read();
20         }
21     }
22 
23     public class Singleton
24     {
25         private static readonly Singleton instance = new Singleton();
26         private Singleton() { }
27         public static Singleton GetInstance()
28         {
29             return instance;
30         }
31     }
32 }
从输出结果可知,两次实例化得到的是同一个对象。
 
 
2.单例模式的特点

单从实现来看,单例模式有以下特点
  • 构造函数访问权限为private,即不允许外界通过调用构造函数实例化;
  • 提供一个静态方法作为该类实例的唯一全局访问点
  • 任何时候只返回一个实例
单例模式UML类图如下
技术分享
 技术分享

 

技术分享
3.懒汉模式

如果在多线程下,能不能保证GetInstance()方法只创建一个实例呢?很显然是不行的。在C#中可以使用lock语句来保证对临界区进行完全访问(所谓的临界区是指在多线程访问共享资源时,使用独占式访问的代码段来对共享资源实施保护的一种手段)。接下来我们看看多线程下的单例模式
 
3.1举例2(多线程时的单例)
 1 namespace 单例模式
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Singleton s1 = Singleton.GetInstance();
 8             Singleton s2 = Singleton.GetInstance();
 9 
10             if (s1 == s2)
11             {
12                 Console.WriteLine("Objects are the same instance");
13             }
14 
15             Console.Read();
16         }
17     }
18 
19     public class Singleton
20     {
21         private static Singleton instance;
22         private static readonly object syncRoot = new object();
23         private Singleton()
24         {
25         }
26 
27         public static Singleton GetInstance()
28         {
29             lock (syncRoot)
30             {
31                 if (instance == null)
32                 {
33                     instance = new Singleton();
34                 }
35             }
36             return instance;
37         }
38     }
39 }

 这个例子能不能保证多线程安全呢?能。最先进入的那个线程会创建对象实例,保证类只实例化一次。但这样每次都lock的话,一旦多次调用时,第一个调用的会进入lock,而其他的线程则需要等待第一个结束才能依次调用,后面的依次调用,等待......所以会导致性能损耗。lock加锁就好比漏斗一样,每次只能样一个线程通过

技术分享

 

技术分享
3.2举例3(多线程下多重锁定的单例)
为了解决例子2中的多次锁定问题,我们进行稍微的改动,同时解决了线程安全和性能的问题。(若没有性能方面的顾虑,这个方法就是杀鸡用了牛刀)
 1 namespace 单例模式
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Singleton s1 = Singleton.GetInstance();
 8             Singleton s2 = Singleton.GetInstance();
 9 
10             if (s1 == s2)
11             {
12                 Console.WriteLine("Objects are the same instance");
13             }
14 
15             Console.Read();
16         }
17     }
18 
19     public class Singleton
20     {
21         private static Singleton instance;
22         private static readonly object syncRoot = new object();
23         private Singleton()
24         {
25         }
26 
27         public static Singleton GetInstance()
28         {
29             if (instance == null)
30             {
31                 lock (syncRoot)
32                 {
33                     if (instance == null)
34                     {
35                         instance = new Singleton();
36                     }
37                 }
38             }
39             return instance;
40         }
41     }
42 }

 

4.饿汉模式
通过静态初始化的方式在类加载时就进行实例化操作,相比于懒汉模式,不存在线程安全的问题,如下
 1 namespace 单例模式
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Singleton s1 = Singleton.GetInstance();
 8             Singleton s2 = Singleton.GetInstance();
 9 
10             if (s1 == s2)
11             {
12                 Console.WriteLine("Objects are the same instance");
13             }
14 
15             Console.Read();
16         }
17     }
18 
19     public sealed class Singleton
20     {
21         private static readonly Singleton instance = new Singleton();
22         private Singleton()
23         {
24         }
25 
26         public static Singleton GetInstance()
27         {
28             return instance;
29         }
30     }
31 }

 

5.饿汉模式 VS 懒汉模式

饿汉模式:即利用静态初始化的方式,类一旦加载就立即实例化。其特点是加载类时比较慢,但运行时比较快,并且线程安全。
懒汉模式:即等到类第一次被引用时,才会对其实例化操作(延迟实例化 )。其特点是加载时比较快,但运行时比较慢,存在线程不安全的问题(需要双重锁定来保证多线程访问的安全性)。
 
今天是坚持晨读的第21天,也把这段时间的知识作下总结,写得不好的地方,欢迎讨论指出。

设计模式之单例模式

标签:

原文地址:http://www.cnblogs.com/Hugh621/p/5820257.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!