首页 > 代码库 > 设计模式之单例模式
设计模式之单例模式
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 Singleton24 {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 Singleton20 {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 Singleton20 {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 Singleton20 {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天,也把这段时间的知识作下总结,写得不好的地方,欢迎讨论指出。
设计模式之单例模式
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。