在现代 C# 开发中,尤其是使用 .NET Core 或 .NET 5+ 构建应用程序时,依赖注入(Dependency Injection, DI) 已成为标准实践。而其中的 单例(Singleton) 生命周期模式因其全局唯一性和资源复用优势被广泛使用。但如果不注意线程安全问题,就可能引发难以排查的并发错误。
本文将手把手教你如何在 C# 依赖注入容器中正确注册和使用线程安全的单例服务,即使是编程新手也能轻松理解!
在 .NET 的依赖注入系统中,服务有三种生命周期:
当你注册一个服务为 AddSingleton 时,DI 容器会确保该服务在整个应用运行期间只有一个实例。这非常适合缓存、配置管理器或日志记录器等场景。
由于单例在整个应用中是共享的,多个线程(例如来自不同 HTTP 请求的线程)可能会同时访问它的成员变量。如果这些操作涉及写入或修改状态,就可能发生 竞态条件(Race Condition),导致数据不一致或程序崩溃。
因此,在设计单例服务时,必须考虑 C#依赖注入 环境下的 单例模式线程安全 问题。
下面是一个典型的非线程安全单例服务:
public class CounterService{ private int _count = 0; public void Increment() { _count++; // 非原子操作!多线程下可能出错 } public int GetCount() => _count;} 如果多个线程同时调用 Increment(),_count++ 操作可能被中断,导致最终结果小于预期。
有多种方式可以保证线程安全。以下是两种常用且简单的方法:
lock 关键字public class ThreadSafeCounterService{ private int _count = 0; private readonly object _lock = new object(); public void Increment() { lock (_lock) { _count++; } } public int GetCount() { lock (_lock) { return _count; } }} 通过 lock,我们确保同一时间只有一个线程能进入临界区,从而避免并发冲突。
Interlocked 类(推荐用于简单操作)using System.Threading;public class InterlockedCounterService{ private int _count = 0; public void Increment() { Interlocked.Increment(ref _count); } public int GetCount() => Volatile.Read(ref _count);} Interlocked.Increment 是原子操作,性能更高,适合简单的数值增减场景。
在 Program.cs(.NET 6+)或 Startup.cs 中注册你的线程安全单例:
// .NET 6+ 示例var builder = WebApplication.CreateBuilder(args);// 注册为单例builder.Services.AddSingleton<ThreadSafeCounterService>();var app = builder.Build();app.MapGet("/count", (ThreadSafeCounterService counter) =>{ counter.Increment(); return $"当前计数: {counter.GetCount()}";});app.Run(); 这样,无论多少用户同时访问 /count 接口,计数器都能安全地工作。
lock、Interlocked、ConcurrentDictionary 等线程安全机制。通过以上方法,你就能在 C# 项目中安全地使用 服务生命周期管理 中的单例模式,构建高性能且稳定的 Web 应用或后台服务。
记住:单例虽好,线程安全不可少!
本文由主机测评网于2025-12-18发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://www.vpshk.cn/2025129438.html