c#-单例模式

[复制链接]
发表于 2025-10-11 21:59:23 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
单例模式是一种创建型计划模式,确保一个类只有一个实例,并提供一个全局访问点来获取该实例。以下是详细先容单例模式的各种实现方式。
1. 饿汉式单例模式

代码示例
  1. using System;
  2. // 饿汉式单例类
  3. public sealed class EagerSingleton
  4. {
  5.     // 静态只读字段,在类加载时就初始化实例
  6.     private static readonly EagerSingleton instance = new EagerSingleton();
  7.     // 私有构造函数,防止外部实例化
  8.     private EagerSingleton()
  9.     {
  10.         Console.WriteLine("EagerSingleton 实例已创建");
  11.     }
  12.     // 公共静态属性,用于获取单例实例
  13.     public static EagerSingleton Instance
  14.     {
  15.         get
  16.         {
  17.             return instance;
  18.         }
  19.     }
  20.     // 示例方法
  21.     public void DoSomething()
  22.     {
  23.         Console.WriteLine("EagerSingleton 正在执行操作");
  24.     }
  25. }
  26. class Program
  27. {
  28.     static void Main()
  29.     {
  30.         // 获取单例实例
  31.         EagerSingleton singleton = EagerSingleton.Instance;
  32.         // 调用示例方法
  33.         singleton.DoSomething();
  34.     }
  35. }
复制代码
案例解读


  • 类加载与实例创建:在 C# 中,当一个类被加载时,其静态成员会被初始化。这里的 private static readonly EagerSingleton instance = new EagerSingleton(); 使得 EagerSingleton 类在加载时就创建了唯一的实例。readonly 关键字包管了这个实例一旦被创建,就不能被重新赋值。
  • 私有构造函数:private EagerSingleton() 克制了外部代码通过 new 关键字创建新的 EagerSingleton 实例,确保了单例的唯一性。
  • 公共静态属性:public static EagerSingleton Instance 提供了一个全局访问点,外部代码可以通过 EagerSingleton.Instance 来获取这个唯一的实例。
优缺点分析


  • 优点:实现简单,线程安全。由于实例在类加载时就创建好了,不存在多线程同时创建实例的标题。
  • 缺点:大概会造成资源浪费。假如这个单例实例在整个应用步伐的生命周期中都没有被使用,那么它仍然会在类加载时被创建,占用体系资源。
2. 懒汉式单例模式(非线程安全)

代码示例
  1. using System;
  2. // 懒汉式单例类(非线程安全)
  3. public sealed class LazySingletonNonThreadSafe
  4. {
  5.     // 静态字段,初始为 null
  6.     private static LazySingletonNonThreadSafe instance;
  7.     // 私有构造函数,防止外部实例化
  8.     private LazySingletonNonThreadSafe()
  9.     {
  10.         Console.WriteLine("LazySingletonNonThreadSafe 实例已创建");
  11.     }
  12.     // 公共静态属性,用于获取单例实例
  13.     public static LazySingletonNonThreadSafe Instance
  14.     {
  15.         get
  16.         {
  17.             if (instance == null)
  18.             {
  19.                 instance = new LazySingletonNonThreadSafe();
  20.             }
  21.             return instance;
  22.         }
  23.     }
  24.     // 示例方法
  25.     public void DoSomething()
  26.     {
  27.         Console.WriteLine("LazySingletonNonThreadSafe 正在执行操作");
  28.     }
  29. }
  30. class Program
  31. {
  32.     static void Main()
  33.     {
  34.         // 获取单例实例
  35.         LazySingletonNonThreadSafe singleton = LazySingletonNonThreadSafe.Instance;
  36.         // 调用示例方法
  37.         singleton.DoSomething();
  38.     }
  39. }
复制代码
案例解读


  • 延长实例化:private static LazySingletonNonThreadSafe instance; 初始化为 null,在第一次调用 Instance 属性时,通过 if (instance == null) 判断实例是否已经创建,假如未创建则创建新实例。这种方式实现了延长加载,只有在必要使用实例时才会创建。
  • 非线程安全标题:在多线程情况下,大概会有多个线程同时进入 if (instance == null) 这个判断语句,从而导致多个线程都创建了新的实例,粉碎了单例的唯一性。
优缺点分析


  • 优点:实现了延长加载,制止了不须要的资源浪费。
  • 缺点:非线程安全,在多线程情况下不能包管单例的唯一性。
3. 懒汉式单例模式(线程安全,简单加锁)

代码示例
  1. using System;
  2. // 懒汉式单例类(线程安全,简单加锁)
  3. public sealed class LazySingletonThreadSafeSimple
  4. {
  5.     // 静态字段,初始为 null
  6.     private static LazySingletonThreadSafeSimple instance;
  7.     // 静态对象,用于加锁
  8.     private static readonly object lockObject = new object();
  9.     // 私有构造函数,防止外部实例化
  10.     private LazySingletonThreadSafeSimple()
  11.     {
  12.         Console.WriteLine("LazySingletonThreadSafeSimple 实例已创建");
  13.     }
  14.     // 公共静态属性,用于获取单例实例
  15.     public static LazySingletonThreadSafeSimple Instance
  16.     {
  17.         get
  18.         {
  19.             lock (lockObject)
  20.             {
  21.                 if (instance == null)
  22.                 {
  23.                     instance = new LazySingletonThreadSafeSimple();
  24.                 }
  25.             }
  26.             return instance;
  27.         }
  28.     }
  29.     // 示例方法
  30.     public void DoSomething()
  31.     {
  32.         Console.WriteLine("LazySingletonThreadSafeSimple 正在执行操作");
  33.     }
  34. }
  35. class Program
  36. {
  37.     static void Main()
  38.     {
  39.         // 获取单例实例
  40.         LazySingletonThreadSafeSimple singleton = LazySingletonThreadSafeSimple.Instance;
  41.         // 调用示例方法
  42.         singleton.DoSomething();
  43.     }
  44. }
复制代码
案例解读


  • 加锁机制:private static readonly object lockObject = new object(); 创建了一个静态的锁对象。在 Instance 属性的 get 方法中,使用 lock (lockObject) 对代码块举行加锁,确保同一时间只有一个线程能进入这个代码块。
  • 线程安全实现:通过加锁,当一个线程进入 lock 代码块时,其他线程会被壅闭,直到该线程完成实例的创建。如许就包管了在多线程情况下实例只会被创建一次。
优缺点分析


  • 优点:实现了线程安全,包管了单例的唯一性。
  • 缺点:每次获取实例都必要加锁,加锁操纵会带来肯定的性能开销。纵然实例已经创建好了,后续的线程访问仍然必要举行加锁操纵,这在高并发场景下会影响性能。
4. 双重查抄锁定单例模式(线程安全)

代码示例
  1. using System;
  2. // 双重检查锁定单例类
  3. public sealed class DoubleCheckedLockingSingleton
  4. {
  5.     // 静态字段,初始为 null
  6.     private static DoubleCheckedLockingSingleton instance;
  7.     // 静态对象,用于加锁
  8.     private static readonly object lockObject = new object();
  9.     // 私有构造函数,防止外部实例化
  10.     private DoubleCheckedLockingSingleton()
  11.     {
  12.         Console.WriteLine("DoubleCheckedLockingSingleton 实例已创建");
  13.     }
  14.     // 公共静态属性,用于获取单例实例
  15.     public static DoubleCheckedLockingSingleton Instance
  16.     {
  17.         get
  18.         {
  19.             if (instance == null)
  20.             {
  21.                 lock (lockObject)
  22.                 {
  23.                     if (instance == null)
  24.                     {
  25.                         instance = new DoubleCheckedLockingSingleton();
  26.                     }
  27.                 }
  28.             }
  29.             return instance;
  30.         }
  31.     }
  32.     // 示例方法
  33.     public void DoSomething()
  34.     {
  35.         Console.WriteLine("DoubleCheckedLockingSingleton 正在执行操作");
  36.     }
  37. }
  38. class Program
  39. {
  40.     static void Main()
  41.     {
  42.         // 获取单例实例
  43.         DoubleCheckedLockingSingleton singleton = DoubleCheckedLockingSingleton.Instance;
  44.         // 调用示例方法
  45.         singleton.DoSomething();
  46.     }
  47. }
复制代码
案例解读


  • 第一次查抄:if (instance == null) 在加锁前先辈行查抄,假如实例已经创建好了,就直接返回实例,制止了不须要的加锁操纵,进步了性能。
  • 加锁与第二次查抄:假如第一次查抄发实际例为 null,则进入 lock (lockObject) 代码块举行加锁。在加锁后,再次举行 if (instance == null) 查抄,防止多个线程同时通过第一次查抄,在一个线程创建实例后,其他线程不会再重复创建。
优缺点分析


  • 优点:既实现了延长加载,又包管了线程安全,同时镌汰了不须要的锁操纵,进步了性能。
  • 缺点:实现相对复杂,必要对多线程编程有肯定的明白。
5. 使用 Lazy<T> 实现单例模式(线程安全)

代码示例
  1. using System;
  2. // 使用 Lazy<T> 实现的单例类
  3. public sealed class LazyGenericSingleton
  4. {
  5.     // 静态只读的 Lazy<T> 实例
  6.     private static readonly Lazy<LazyGenericSingleton> lazy = new Lazy<LazyGenericSingleton>(() => new LazyGenericSingleton());
  7.     // 私有构造函数,防止外部实例化
  8.     private LazyGenericSingleton()
  9.     {
  10.         Console.WriteLine("LazyGenericSingleton 实例已创建");
  11.     }
  12.     // 公共静态属性,用于获取单例实例
  13.     public static LazyGenericSingleton Instance
  14.     {
  15.         get
  16.         {
  17.             return lazy.Value;
  18.         }
  19.     }
  20.     // 示例方法
  21.     public void DoSomething()
  22.     {
  23.         Console.WriteLine("LazyGenericSingleton 正在执行操作");
  24.     }
  25. }
  26. class Program
  27. {
  28.     static void Main()
  29.     {
  30.         // 获取单例实例
  31.         LazyGenericSingleton singleton = LazyGenericSingleton.Instance;
  32.         // 调用示例方法
  33.         singleton.DoSomething();
  34.     }
  35. }
复制代码
案例解读


  • Lazy<T> 类的使用:private static readonly Lazy<LazyGenericSingleton> lazy = new Lazy<LazyGenericSingleton>(() => new LazyGenericSingleton()); 创建了一个 Lazy<T> 实例,使用委托 () => new LazyGenericSingleton() 指定了实例的创建方式。
  • 延长加载与线程安全:Lazy<T> 类会在第一次访问 lazy.Value 时才创建实例,实现了延长加载。同时,Lazy<T> 类内部处理处罚了线程安全标题,确保实例只被创建一次。
优缺点分析


  • 优点:实现简单,代码简便,同时包管了延长加载和线程安全。
  • 缺点:依赖于 .NET 框架的 Lazy<T> 类,假如必要在不支持该类的情况中使用,就无法采取这种实现方式。
6. 静态内部类实现单例模式(线程安全)

代码示例
  1. using System;
  2. // 静态内部类实现的单例类
  3. public sealed class StaticNestedClassSingleton
  4. {
  5.     // 私有构造函数,防止外部实例化
  6.     private StaticNestedClassSingleton()
  7.     {
  8.         Console.WriteLine("StaticNestedClassSingleton 实例已创建");
  9.     }
  10.     // 静态内部类
  11.     private static class Nested
  12.     {
  13.         // 静态只读字段,保存单例实例
  14.         internal static readonly StaticNestedClassSingleton Instance = new StaticNestedClassSingleton();
  15.     }
  16.     // 公共静态属性,用于获取单例实例
  17.     public static StaticNestedClassSingleton Instance
  18.     {
  19.         get
  20.         {
  21.             return Nested.Instance;
  22.         }
  23.     }
  24.     // 示例方法
  25.     public void DoSomething()
  26.     {
  27.         Console.WriteLine("StaticNestedClassSingleton 正在执行操作");
  28.     }
  29. }
  30. class Program
  31. {
  32.     static void Main()
  33.     {
  34.         // 获取单例实例
  35.         StaticNestedClassSingleton singleton = StaticNestedClassSingleton.Instance;
  36.         // 调用示例方法
  37.         singleton.DoSomething();
  38.     }
  39. }
复制代码
案例解读


  • 静态内部类的特性:在 C# 中,静态内部类只会在第一次被使用时加载。private static class Nested 是一个静态内部类,此中的 internal static readonly StaticNestedClassSingleton Instance = new StaticNestedClassSingleton(); 在类加载时创建了 StaticNestedClassSingleton 的实例。
  • 延长加载与线程安全:当第一次访问 StaticNestedClassSingleton.Instance 时,会触发 Nested 类的加载,从而创建单例实例。由于静态类的加载是线程安全的,以是这种方式实现了延长加载和线程安全。
优缺点分析


  • 优点:实现简单,代码简便,同时包管了延长加载和线程安全。
  • 缺点:对于不熟悉静态内部类特性的开发者来说,大概不太容易明白。
7. 通过 Mutex 实现单例模式(体系级单例)

代码示例
  1. using System;
  2. using System.Threading;
  3. // 通过 Mutex 实现的单例类
  4. public sealed class MutexSingleton
  5. {
  6.     // 静态字段,保存单例实例
  7.     private static MutexSingleton instance;
  8.     // 静态 Mutex 实例
  9.     private static readonly Mutex mutex = new Mutex(true, "MutexSingleton");
  10.     // 私有构造函数,防止外部实例化
  11.     private MutexSingleton()
  12.     {
  13.         Console.WriteLine("MutexSingleton 实例已创建");
  14.     }
  15.     // 公共静态属性,用于获取单例实例
  16.     public static MutexSingleton Instance
  17.     {
  18.         get
  19.         {
  20.             if (instance == null)
  21.             {
  22.                 mutex.WaitOne();
  23.                 try
  24.                 {
  25.                     if (instance == null)
  26.                     {
  27.                         instance = new MutexSingleton();
  28.                     }
  29.                 }
  30.                 finally
  31.                 {
  32.                     mutex.ReleaseMutex();
  33.                 }
  34.             }
  35.             return instance;
  36.         }
  37.     }
  38.     // 示例方法
  39.     public void DoSomething()
  40.     {
  41.         Console.WriteLine("MutexSingleton 正在执行操作");
  42.     }
  43. }
  44. class Program
  45. {
  46.     static void Main()
  47.     {
  48.         // 获取单例实例
  49.         MutexSingleton singleton = MutexSingleton.Instance;
  50.         // 调用示例方法
  51.         singleton.DoSomething();
  52.     }
  53. }
复制代码
案例解读


  • Mutex 的使用:private static readonly Mutex mutex = new Mutex(true, "MutexSingleton"); 创建了一个定名的 Mutex 实例,true 表现创建线程拥有互斥体的初始全部权,"MutexSingleton" 是互斥体的名称,确保在整个体系中具有唯一性。
  • 线程同步与实例创建:在 Instance 属性的 get 方法中,mutex.WaitOne() 期待获取互斥量,假如获取到则进入临界区。在临界区内,再次查抄实例是否为 null,假如为 null 则创建实例。末了,使用 mutex.ReleaseMutex() 开释互斥量,答应其他线程或历程获取该互斥量。
优缺点分析


  • 优点:可以确保在整个体系中只有一个实例运行,常用于确保应用步伐只有一个历程实例。
  • 缺点:Mutex 是一个体系级的同步原语,使用它会带来肯定的性能开销。而且,假如互斥量被非常占用,大概会导致步伐出现死锁等标题。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表