c#-单例模式

单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点来获取该实例。以下是详细介绍单例模式的各种实现方式。

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
{// 静态字段,初始为 nullprivate 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
{// 静态字段,初始为 nullprivate 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
{// 静态字段,初始为 nullprivate 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 是一个系统级的同步原语,使用它会带来一定的性能开销。而且,如果互斥量被异常占用,可能会导致程序出现死锁等问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/36997.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

「实战指南 」Swift 并发中的任务取消机制

网罗开发 &#xff08;小红书、快手、视频号同名&#xff09; 大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等…

实验12深度学习

实验12深度学习 一、实验目的 &#xff08;1&#xff09;理解并熟悉深度神经网络的工作原理&#xff1b; &#xff08;2&#xff09;熟悉常用的深度神经网络模型及其应用环境&#xff1b; &#xff08;3&#xff09;掌握Anaconda的安装和设置方法&#xff0c;进一步熟悉Jupyte…

【问题解决】Postman 测试报错 406

现象 Tomcat 日志 org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.logException Resolved org.springframework.web.HttpMediaTypeNotAcceptableException: No acceptable representation HTTP状态 406 - 不可接收 的报错&#xff0c;核心原因 客…

微信小程序:用户拒绝小程序获取当前位置后的处理办法

【1】问题描述&#xff1a; 小程序在调用 wx.getLocation() 获取用地理位置时&#xff0c;如果用户选择拒绝授权&#xff0c;代码会直接抛出错误。如果再次调用 wx.getLocation() 时&#xff0c;就不会在弹窗询问用户是否允许授权。导致用户想要重新允许获取地理位置时&#x…

【MySQL】内置函数

目录 一、日期时间函数1.1 简单使用1.2 案例实操 二、字符串函数2.1 简单使用2.2 案例实践2.2.1 获取emp表的ename列的字符集2.2.2 要求显示exam_result表中的信息&#xff0c;显示格式&#xff1a;“XXX的语文是XXX分&#xff0c;数学XXX分&#xff0c;英语XXX分”2.2.3 求exa…

模块二 单元4 安装AD+DC

模块二 单元4 安装ADDC 两个任务&#xff1a; 1.安装AD活动目录 2.升级当前服务器为DC域控制器 安装前的准备工作&#xff1a; 确定你要操作的服务器系统&#xff08;Windows server 2022&#xff09;&#xff1b; 之前的服务器系统默认是工作组的模式workgroup模式&#xff08…

卫星互联网智慧杆:开启智能城市新时代​

哇哦&#xff01;在当下这个数字化浪潮正以雷霆万钧之势席卷全球的超酷时代&#xff0c;智慧城市建设已然成为世界各国你追我赶、竞相发力的核心重点领域啦&#xff01;而咱们的卫星互联网智慧杆&#xff0c;作为一项完美融合了卫星通信与物联网顶尖技术的创新结晶&#xff0c;…

ThreadLocal 的详细使用指南

一、ThreadLocal 核心原理 ThreadLocal 是 Java 提供的线程绑定机制&#xff0c;为每个线程维护变量的独立副本。其内部通过 ThreadLocalMap 实现&#xff0c;每个线程的 Thread 对象都有一个独立的 ThreadLocalMap&#xff0c;存储以 ThreadLocal 对象为键、线程局部变量为值…

免费开源的NAS解决方案:TrueNAS

TrueNAS是业内知名的FreeNAS系统的升级版&#xff0c;是一款开源的网络存储系统&#xff0c;具有高性能、稳定性和易用性等优点。 TrueNAS目前有三个版本&#xff0c;分别是TrueNAS CORE、TrueNAS ENTERPRISE、TrueNAS SCALE。其中&#xff0c;TrueNAS CORE基于FreeBSD开发&…

Fisher 信息矩阵公式原理:使用似然估计,二阶导数等知识点

Fisher 信息矩阵公式原理:使用似然估计,二阶导数等知识点 目录 Fisher 信息矩阵公式原理:使用似然估计,二阶导数等知识点Fisher 通过似然估计求解真实数据和权重参数之间的差异**1. Fisher 信息矩阵的定义****2. 计算对数似然函数的二阶导数****3. 代入 Fisher 信息矩阵定义…

自定义myshell(精讲)

我们都知道&#xff0c;我们给Linux下发的指令都是shell帮我们处理并完成的&#xff0c;那么他是怎么完成的呢&#xff1f;不难想到他都是通过环境变量以及程序替换来完成的。我们这一篇文章就手把手来教你怎么自己实现一个简单的shell。 目标&#xff1a; 1.要能处理普通命令 …

HTML图像标签的详细介绍

1. 常用图像格式 格式特点适用场景JPEG有损压缩&#xff0c;文件小&#xff0c;不支持透明适合照片、复杂图像PNG无损压缩&#xff0c;支持透明&#xff08;Alpha通道&#xff09;适合图标、需要透明背景的图片GIF支持动画&#xff0c;最多256色简单动画、低色彩图标WebP谷歌开…

信号的捕捉(操作部分)

目录 信号集和信号屏蔽字 信号集 信号屏蔽字 信号位操作函数 sigemptyset sigaddset sigismember sigprocmask sigpending 手动操作让2号信号屏蔽打印pending 信号处理函数sigaction 我们继续来学习信号的捕捉 信号集和信号屏蔽字 信号集 信号集是存储一组信号的…

CIR-Net:用于 RGB-D 显著性目标检测的跨模态交互与优化(问题)

摘要 问题一&#xff1a;自模态注意力优化单元和跨模态加权优化单元什么意思&#xff1f; 1 优化中间件结构的作用 位置&#xff1a;位于编码器和解码器之间 输入&#xff1a;编码器提取的RGB特征&#xff0c;深度特征以及RGB-D特征。 输出&#xff1a;经过优化的RGB&…

Linux驱动开发基础(can)

目录 1.can的介绍 2.can的硬件连接 2.1 CPU自带can控制器 2.2 CPU没有can控制器 3.电气属性 4.can的特点 5.can协议 5.1 can的种类 5.2 数据帧 5.2.1 标准数据帧格式 5.3.1 扩展数据帧格式 5.3 遥控帧 5.4 错误帧 5.5 过载帧 5.6 帧间隔 5.7 位填充 5.8 位时…

【北京迅为】iTOP-RK3568开发板OpenHarmony系统南向驱动开发UART接口运作机制

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…

【嵌入式学习】时钟 - 边缘触发锁存器

目录 ## 时钟 ## 带边缘触发的寄存器 ## 优化内存走线 ## 画16位的内存 ## 时钟 波特率&#xff1a;一分钟说几个字 clock统一计算机内部的节奏&#xff0c;clock频率越高cpu速度越快 触发&#xff1a;电压的突变&#xff1b;下降沿&#xff1a;高变低&#xff1b;上升沿…

Linux C/C++编程——线程

线程是允许应用程序并发执行多个任务的一种机制&#xff0c;线程参与系统调度。 系统调度的最小单元是线程、而并非进程。 线程包含在进程之中&#xff0c;是进程中的实际运行单位。一个线程指的是进程中一个单一顺序的控制流&#xff08;或者说是执行路线、执行流&#xff09;…

CAN通信转TCP/IP通信协议解析

背景&#xff1a;最近项目开发受限于开发版只有一路CAN口和多个CAN通信对象的帧ID一样&#xff0c;考虑采用转换模块将CAN通信转成TCP/IP通信&#xff0c;间接实现获取CAN报文数据的目的。 1. 转换模块协议 首先想到的是采购周立功他家的多路CAN通信转TCP/IP通信模块&#xf…

vue:组件的使用

Vue&#xff1a;组件的使用 1、什么是组件 1.1、传统方式开发的应用 一个网页通常包括三部分&#xff1a;结构&#xff08;HTML&#xff09;、样式&#xff08;CSS&#xff09;、交互&#xff08;JavaScript&#xff09;。在传统开发模式下&#xff0c;随着项目规模的增大&a…