马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
单例模式是一种创建型计划模式,确保一个类只有一个实例,并提供一个全局访问点来获取该实例。以下是详细先容单例模式的各种实现方式。
1. 饿汉式单例模式
代码示例
- using System;
- // 饿汉式单例类
- public sealed class EagerSingleton
- {
- // 静态只读字段,在类加载时就初始化实例
- private static readonly EagerSingleton instance = new EagerSingleton();
- // 私有构造函数,防止外部实例化
- private EagerSingleton()
- {
- Console.WriteLine("EagerSingleton 实例已创建");
- }
- // 公共静态属性,用于获取单例实例
- public static EagerSingleton Instance
- {
- get
- {
- return instance;
- }
- }
- // 示例方法
- public void DoSomething()
- {
- Console.WriteLine("EagerSingleton 正在执行操作");
- }
- }
- class Program
- {
- static void Main()
- {
- // 获取单例实例
- EagerSingleton singleton = EagerSingleton.Instance;
- // 调用示例方法
- singleton.DoSomething();
- }
- }
复制代码 案例解读
- 类加载与实例创建:在 C# 中,当一个类被加载时,其静态成员会被初始化。这里的 private static readonly EagerSingleton instance = new EagerSingleton(); 使得 EagerSingleton 类在加载时就创建了唯一的实例。readonly 关键字包管了这个实例一旦被创建,就不能被重新赋值。
- 私有构造函数:private EagerSingleton() 克制了外部代码通过 new 关键字创建新的 EagerSingleton 实例,确保了单例的唯一性。
- 公共静态属性:public static EagerSingleton Instance 提供了一个全局访问点,外部代码可以通过 EagerSingleton.Instance 来获取这个唯一的实例。
优缺点分析
- 优点:实现简单,线程安全。由于实例在类加载时就创建好了,不存在多线程同时创建实例的标题。
- 缺点:大概会造成资源浪费。假如这个单例实例在整个应用步伐的生命周期中都没有被使用,那么它仍然会在类加载时被创建,占用体系资源。
2. 懒汉式单例模式(非线程安全)
代码示例
- using System;
- // 懒汉式单例类(非线程安全)
- public sealed class LazySingletonNonThreadSafe
- {
- // 静态字段,初始为 null
- private static LazySingletonNonThreadSafe instance;
- // 私有构造函数,防止外部实例化
- private LazySingletonNonThreadSafe()
- {
- Console.WriteLine("LazySingletonNonThreadSafe 实例已创建");
- }
- // 公共静态属性,用于获取单例实例
- public static LazySingletonNonThreadSafe Instance
- {
- get
- {
- if (instance == null)
- {
- instance = new LazySingletonNonThreadSafe();
- }
- return instance;
- }
- }
- // 示例方法
- public void DoSomething()
- {
- Console.WriteLine("LazySingletonNonThreadSafe 正在执行操作");
- }
- }
- class Program
- {
- static void Main()
- {
- // 获取单例实例
- LazySingletonNonThreadSafe singleton = LazySingletonNonThreadSafe.Instance;
- // 调用示例方法
- singleton.DoSomething();
- }
- }
复制代码 案例解读
- 延长实例化:private static LazySingletonNonThreadSafe instance; 初始化为 null,在第一次调用 Instance 属性时,通过 if (instance == null) 判断实例是否已经创建,假如未创建则创建新实例。这种方式实现了延长加载,只有在必要使用实例时才会创建。
- 非线程安全标题:在多线程情况下,大概会有多个线程同时进入 if (instance == null) 这个判断语句,从而导致多个线程都创建了新的实例,粉碎了单例的唯一性。
优缺点分析
- 优点:实现了延长加载,制止了不须要的资源浪费。
- 缺点:非线程安全,在多线程情况下不能包管单例的唯一性。
3. 懒汉式单例模式(线程安全,简单加锁)
代码示例
- using System;
- // 懒汉式单例类(线程安全,简单加锁)
- public sealed class LazySingletonThreadSafeSimple
- {
- // 静态字段,初始为 null
- private static LazySingletonThreadSafeSimple instance;
- // 静态对象,用于加锁
- private static readonly object lockObject = new object();
- // 私有构造函数,防止外部实例化
- private LazySingletonThreadSafeSimple()
- {
- Console.WriteLine("LazySingletonThreadSafeSimple 实例已创建");
- }
- // 公共静态属性,用于获取单例实例
- public static LazySingletonThreadSafeSimple Instance
- {
- get
- {
- lock (lockObject)
- {
- if (instance == null)
- {
- instance = new LazySingletonThreadSafeSimple();
- }
- }
- return instance;
- }
- }
- // 示例方法
- public void DoSomething()
- {
- Console.WriteLine("LazySingletonThreadSafeSimple 正在执行操作");
- }
- }
- class Program
- {
- static void Main()
- {
- // 获取单例实例
- LazySingletonThreadSafeSimple singleton = LazySingletonThreadSafeSimple.Instance;
- // 调用示例方法
- singleton.DoSomething();
- }
- }
复制代码 案例解读
- 加锁机制:private static readonly object lockObject = new object(); 创建了一个静态的锁对象。在 Instance 属性的 get 方法中,使用 lock (lockObject) 对代码块举行加锁,确保同一时间只有一个线程能进入这个代码块。
- 线程安全实现:通过加锁,当一个线程进入 lock 代码块时,其他线程会被壅闭,直到该线程完成实例的创建。如许就包管了在多线程情况下实例只会被创建一次。
优缺点分析
- 优点:实现了线程安全,包管了单例的唯一性。
- 缺点:每次获取实例都必要加锁,加锁操纵会带来肯定的性能开销。纵然实例已经创建好了,后续的线程访问仍然必要举行加锁操纵,这在高并发场景下会影响性能。
4. 双重查抄锁定单例模式(线程安全)
代码示例
- using System;
- // 双重检查锁定单例类
- public sealed class DoubleCheckedLockingSingleton
- {
- // 静态字段,初始为 null
- private static DoubleCheckedLockingSingleton instance;
- // 静态对象,用于加锁
- private static readonly object lockObject = new object();
- // 私有构造函数,防止外部实例化
- private DoubleCheckedLockingSingleton()
- {
- Console.WriteLine("DoubleCheckedLockingSingleton 实例已创建");
- }
- // 公共静态属性,用于获取单例实例
- public static DoubleCheckedLockingSingleton Instance
- {
- get
- {
- if (instance == null)
- {
- lock (lockObject)
- {
- if (instance == null)
- {
- instance = new DoubleCheckedLockingSingleton();
- }
- }
- }
- return instance;
- }
- }
- // 示例方法
- public void DoSomething()
- {
- Console.WriteLine("DoubleCheckedLockingSingleton 正在执行操作");
- }
- }
- class Program
- {
- static void Main()
- {
- // 获取单例实例
- DoubleCheckedLockingSingleton singleton = DoubleCheckedLockingSingleton.Instance;
- // 调用示例方法
- singleton.DoSomething();
- }
- }
复制代码 案例解读
- 第一次查抄:if (instance == null) 在加锁前先辈行查抄,假如实例已经创建好了,就直接返回实例,制止了不须要的加锁操纵,进步了性能。
- 加锁与第二次查抄:假如第一次查抄发实际例为 null,则进入 lock (lockObject) 代码块举行加锁。在加锁后,再次举行 if (instance == null) 查抄,防止多个线程同时通过第一次查抄,在一个线程创建实例后,其他线程不会再重复创建。
优缺点分析
- 优点:既实现了延长加载,又包管了线程安全,同时镌汰了不须要的锁操纵,进步了性能。
- 缺点:实现相对复杂,必要对多线程编程有肯定的明白。
5. 使用 Lazy<T> 实现单例模式(线程安全)
代码示例
- using System;
- // 使用 Lazy<T> 实现的单例类
- public sealed class LazyGenericSingleton
- {
- // 静态只读的 Lazy<T> 实例
- private static readonly Lazy<LazyGenericSingleton> lazy = new Lazy<LazyGenericSingleton>(() => new LazyGenericSingleton());
- // 私有构造函数,防止外部实例化
- private LazyGenericSingleton()
- {
- Console.WriteLine("LazyGenericSingleton 实例已创建");
- }
- // 公共静态属性,用于获取单例实例
- public static LazyGenericSingleton Instance
- {
- get
- {
- return lazy.Value;
- }
- }
- // 示例方法
- public void DoSomething()
- {
- Console.WriteLine("LazyGenericSingleton 正在执行操作");
- }
- }
- class Program
- {
- static void Main()
- {
- // 获取单例实例
- LazyGenericSingleton singleton = LazyGenericSingleton.Instance;
- // 调用示例方法
- singleton.DoSomething();
- }
- }
复制代码 案例解读
- 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. 静态内部类实现单例模式(线程安全)
代码示例
- using System;
- // 静态内部类实现的单例类
- public sealed class StaticNestedClassSingleton
- {
- // 私有构造函数,防止外部实例化
- private StaticNestedClassSingleton()
- {
- Console.WriteLine("StaticNestedClassSingleton 实例已创建");
- }
- // 静态内部类
- private static class Nested
- {
- // 静态只读字段,保存单例实例
- internal static readonly StaticNestedClassSingleton Instance = new StaticNestedClassSingleton();
- }
- // 公共静态属性,用于获取单例实例
- public static StaticNestedClassSingleton Instance
- {
- get
- {
- return Nested.Instance;
- }
- }
- // 示例方法
- public void DoSomething()
- {
- Console.WriteLine("StaticNestedClassSingleton 正在执行操作");
- }
- }
- class Program
- {
- static void Main()
- {
- // 获取单例实例
- StaticNestedClassSingleton singleton = StaticNestedClassSingleton.Instance;
- // 调用示例方法
- singleton.DoSomething();
- }
- }
复制代码 案例解读
- 静态内部类的特性:在 C# 中,静态内部类只会在第一次被使用时加载。private static class Nested 是一个静态内部类,此中的 internal static readonly StaticNestedClassSingleton Instance = new StaticNestedClassSingleton(); 在类加载时创建了 StaticNestedClassSingleton 的实例。
- 延长加载与线程安全:当第一次访问 StaticNestedClassSingleton.Instance 时,会触发 Nested 类的加载,从而创建单例实例。由于静态类的加载是线程安全的,以是这种方式实现了延长加载和线程安全。
优缺点分析
- 优点:实现简单,代码简便,同时包管了延长加载和线程安全。
- 缺点:对于不熟悉静态内部类特性的开发者来说,大概不太容易明白。
7. 通过 Mutex 实现单例模式(体系级单例)
代码示例
- using System;
- using System.Threading;
- // 通过 Mutex 实现的单例类
- public sealed class MutexSingleton
- {
- // 静态字段,保存单例实例
- private static MutexSingleton instance;
- // 静态 Mutex 实例
- private static readonly Mutex mutex = new Mutex(true, "MutexSingleton");
- // 私有构造函数,防止外部实例化
- private MutexSingleton()
- {
- Console.WriteLine("MutexSingleton 实例已创建");
- }
- // 公共静态属性,用于获取单例实例
- public static MutexSingleton Instance
- {
- get
- {
- if (instance == null)
- {
- mutex.WaitOne();
- try
- {
- if (instance == null)
- {
- instance = new MutexSingleton();
- }
- }
- finally
- {
- mutex.ReleaseMutex();
- }
- }
- return instance;
- }
- }
- // 示例方法
- public void DoSomething()
- {
- Console.WriteLine("MutexSingleton 正在执行操作");
- }
- }
- class Program
- {
- static void Main()
- {
- // 获取单例实例
- MutexSingleton singleton = MutexSingleton.Instance;
- // 调用示例方法
- singleton.DoSomething();
- }
- }
复制代码 案例解读
- Mutex 的使用:private static readonly Mutex mutex = new Mutex(true, "MutexSingleton"); 创建了一个定名的 Mutex 实例,true 表现创建线程拥有互斥体的初始全部权,"MutexSingleton" 是互斥体的名称,确保在整个体系中具有唯一性。
- 线程同步与实例创建:在 Instance 属性的 get 方法中,mutex.WaitOne() 期待获取互斥量,假如获取到则进入临界区。在临界区内,再次查抄实例是否为 null,假如为 null 则创建实例。末了,使用 mutex.ReleaseMutex() 开释互斥量,答应其他线程或历程获取该互斥量。
优缺点分析
- 优点:可以确保在整个体系中只有一个实例运行,常用于确保应用步伐只有一个历程实例。
- 缺点:Mutex 是一个体系级的同步原语,使用它会带来肯定的性能开销。而且,假如互斥量被非常占用,大概会导致步伐出现死锁等标题。
|