C#面试题更新 2026-08-05

请说明在 C# 中实现线程安全单例模式(Singleton)的常用方式,并比较它们的适用场景与线程安全保证。

技术原理方案权衡C#

考察说明

考查对 C# 并发编程中单例模式线程安全实现的理解及不同方案优劣的权衡。

回答思路

  1. 【回答框架 1】线程安全的单例模式核心在于确保实例唯一性和初始化过程的原子性。常见实现包括:加锁、静态初始化、Lazy<T> 等。
  2. 【回答框架 2】加锁方式:使用双重检查锁定(Double-Check Locking),在获取实例时先判断实例是否为空,为空则进入锁,再次判断并创建实例。需注意使用 volatile 关键字防止指令重排序导致的问题。
  3. 【回答框架 3】静态初始化方式:利用 CLR 的静态字段初始化保证线程安全,通过私有静态字段在首次访问时由 CLR 负责创建实例,无需显式加锁,但只能通过静态构造函数或静态字段初始化控制时机。
  4. 【回答框架 4】Lazy<T> 方式:使用 .NET 提供的 Lazy<T> 类型,默认使用 ExecutionAndPublication 模式确保只有一个线程执行初始化,同时支持延迟加载,是简洁且线程安全的选择。
  5. 【回答框架 5】性能与适用场景:加锁方式适用于需要精确控制初始化时机的场景;静态初始化代码简单但初始化时机不易掌控;Lazy<T> 既保证延迟加载又线程安全,推荐使用。
  6. 【关键点 1】双重检查锁定需配合 volatile 关键字保证可见性和禁止重排序。
  7. 【关键点 2】静态初始化由 CLR 保证线程安全,代码简洁但无法控制初始化时机。
  8. 【关键点 3】Lazy<T> 是线程安全且延迟加载的推荐方式,默认线程安全模式适合大多数场景。
  9. 【易错点 1】忘记使用 volatile 可能导致多线程下获取到未完全构造的实例。
  10. 【易错点 2】过度使用加锁影响性能,且锁粒度控制不当可能引入死锁。
  11. 【易错点 3】静态初始化方式若在静态构造函数中抛出异常,会导致类型无法使用。