当前位置: 首页 > article >正文

C#中单例模式CSingleton

在 C# 中,单例模式是一种设计模式,确保一个类只有一个实例,并提供全局访问点。单例模式常用于需要全局共享某个资源或对象的场景,如数据库连接、日志记录器等。

懒汉式(Lazy Initialization)单例模式

这种方式下,实例只会在第一次需要的时候创建,并且使用 lock 关键字来保证线程安全。

public class Singleton
{
    // 静态变量保存单例实例
    private static Singleton instance = null;

    // 静态锁对象,用于确保线程安全
    private static readonly object lockObj = new object();

    // 私有构造函数,防止外部实例化
    private Singleton()
    {
    }

    // 公共静态方法,用于获取单例实例
    public static Singleton Instance
    {
        get
        {
            // 双重检查锁定(Double-checked Locking)
            if (instance == null)
            {
                lock (lockObj)
                {
                    if (instance == null)
                    {
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }

    // 示例方法
    public void DoSomething()
    {
        Console.WriteLine("Singleton is working.");
    }
}

饿汉式(Eager Initialization)单例模式

public class Singleton
{
    // 静态变量保存单例实例,并在类加载时创建实例
    private static readonly Singleton instance = new Singleton();

    // 私有构造函数,防止外部实例化
    private Singleton()
    {
    }

    // 公共静态方法,用于获取单例实例
    public static Singleton Instance
    {
        get
        {
            return instance;
        }
    }

    // 示例方法
    public void DoSomething()
    {
        Console.WriteLine("Singleton is working.");
    }
}

两种单例模式的使用都是一样的:

class Program
{
    static void Main(string[] args)
    {
        Singleton singleton = Singleton.Instance;
        singleton.DoSomething();  // 输出:Singleton is working.
    }
}

使用 Lazy 实现懒加载的线程安全单例

C# 中有一个内置的 Lazy<T> 类型,专门用于实现懒加载。使用它可以大大简化懒汉式单例的实现,并且它自带线程安全。

public class Singleton
{
    // 使用 Lazy<T> 实现线程安全的懒加载
    private static readonly Lazy<Singleton> lazyInstance = new Lazy<Singleton>(() => new Singleton());

    // 私有构造函数,防止外部实例化
    private Singleton()
    {
    }

    // 公共静态方法,用于获取单例实例
    public static Singleton Instance
    {
        get
        {
            return lazyInstance.Value;
        }
    }

    // 示例方法
    public void DoSomething()
    {
        Console.WriteLine("Singleton is working.");
    }
}

单例模式的使用场景

单例模式常用于以下场景:

  1. 全局管理资源:如数据库连接池、日志记录器等全局共享的资源。
  2. 配置管理:某些应用程序全局配置只需要一个实例,例如读取配置文件。
  3. 线程池:用于管理线程的全局共享资源。
  4. 缓存:如果应用程序需要缓存一些数据,全局缓存管理器通常是一个单例。

优缺点

优点:

内存优化:确保只创建一个实例,节约系统资源。
全局访问:可以通过全局访问点获取实例,方便管理全局状态。
缺点:

隐藏依赖:使用单例模式时,全局状态可能变得不透明,导致代码难以测试和维护。
并发问题:如果单例对象负责多线程操作,必须保证线程安全,否则容易引发并发问题。

两种单例模式的区别

选择 懒汉式 还是 饿汉式 单例模式取决于具体的需求和场景,尤其是应用程序的性能、资源管理以及线程安全的考虑。

懒汉式单例(Lazy Initialization)

第一次需要时才会创建实例,通常使用 lock 机制来保证线程安全。以下是适合使用懒汉式单例的场景:

适用场景:

  • 资源消耗大:如果实例的创建过程非常耗费资源(如需要加载大量数据或进行复杂的计算),那么使用懒汉式更为合适。这样可以避免在程序启动时就消耗大量资源,只有在需要使用时才初始化对象。

  • 不确定实例是否会被使用:如果有可能该实例在程序的生命周期内不一定会被用到,那么使用懒汉式可以避免在程序启动时创建不必要的实例。例如,某个功能模块可能只在特定条件下才会被使用。

  • 延迟加载优化:在某些场景下,延迟加载(Lazy Loading)有助于优化启动时间,避免过早加载未使用的对象,这可以提升程序启动性能。
    优点

  • 避免不必要的资源消耗。

  • 按需加载,提升启动性能。
    缺点:

  • 实现稍微复杂,需要使用双重检查锁定(Double-Checked Locking)来确保线程安全。

  • 在多线程环境中可能增加锁定带来的开销,尤其是访问频繁时。

饿汉式单例(Eager Initialization)

饿汉式单例是在类加载时立即创建实例,且是线程安全的,因为 .NET 运行时会确保静态字段的初始化是线程安全的。

适用场景:

  • 创建实例开销小:如果单例实例的创建过程不会消耗太多资源,并且实例总是会被使用,那么饿汉式是更为合适的选择。这样可以简化实现,不需要进行线程同步处理。

  • 确定实例总是会被使用:如果你知道该单例类在应用程序中肯定会被使用,并且尽早创建实例有助于提高性能,那么使用饿汉式更为合适。例如,某些全局的配置管理器、日志系统等全局资源通常在应用程序启动时就需要初始化。

  • 需要线程安全且没有复杂的初始化逻辑:饿汉式的实现天然是线程安全的,且避免了懒汉式中为确保线程安全而引入的锁定开销。
    优点:

  • 实现简单,不需要考虑线程同步问题。

  • 无需延迟加载,适用于那些程序一启动就会使用到的单例对象。
    缺点:

  • 即使不需要使用该实例,也会在程序启动时占用资源,可能造成浪费。

  • 如果实例创建过程比较复杂,可能会影响程序的启动速度。

场景/因素懒汉式单例饿汉式单例
资源消耗创建实例开销较大时优先选择创建实例开销小可以考虑使用
使用频率可能不一定使用单例,按需创建实例确定会使用单例,在程序启动时就创建实例
程序启动性能程序启动时不创建单例,避免影响启动性能程序启动时创建实例,可能影响启动速度
线程安全需要考虑线程安全,通常需要加锁线程安全由静态初始化机制自动保证
实现复杂度需要更复杂的代码结构,双重检查锁定等实现简单,直接在类加载时创建实例

总的来说:
懒汉式 适用于 资源消耗较大且不确定是否会使用 的单例实例,能够在需要时才进行创建,避免资源浪费。
饿汉式 适用于 资源消耗较小且确定一定会使用 的单例实例,能够简化实现,提升线程安全性。


http://www.kler.cn/a/312320.html

相关文章:

  • 【2024最新】基于springboot+vue的闲一品交易平台lw+ppt
  • ISAAC SIM踩坑记录--ubuntu 22.04操作系统安装
  • Qt 实现文件监控程序
  • vwmare虚拟机繁忙的解决办法
  • learn-F12 Performance(性能)前端性能分析(LCP,CLS,INP)
  • 将大型语言模型(如GPT-4)微调用于文本续写任务
  • 前端如何快速调试线上问题
  • react的组件的概念和使用
  • 家庭聚餐:用白酒传递亲情与温暖
  • 滚雪球学SpringCloud[4.2讲]: Zuul:Netflix API Gateway详解
  • 浅谈vue2.0与vue3.0的区别(整理十六点)
  • npm run build报Cannot find module错误的解决方法
  • 誉龙视音频 Third/TimeSyn 远程命令执行复现
  • weblogic CVE-2020-14882 靶场攻略
  • 【百日算法计划】:每日一题,见证成长(018)
  • pytorch使用技巧
  • Designify——AI优化图像设计,自动去背景、调整构图、添加视觉效果,创建高质量的设计图像
  • 2024 Oracle CloudWorld的信息量实在太大了
  • Pikachu靶场之XSS
  • Leetcode面试经典150题-97.交错字符串
  • 记一次kafka消息丢失问题排查
  • [SDX35+WCN6856]SDX35 + WCN6856 WiFi可以up起来之后无法扫描到SSID
  • 7.sklearn-逻辑回归、精确率和召回率、ROC曲线和AUC指标
  • Java项目: 基于SpringBoot+mybatis+maven旅游管理系统(含源码+数据库+毕业论文)
  • nvm node管理工具常用指令
  • 编程基础:函数栈帧的创建和销毁