请说明在 C# 中利用 Lazy<T> 实现线程安全延迟初始化的具体做法,并解释其内部机制与适用场景。
考察说明
考查对 C# Lazy<T> 线程安全初始化机制的理解与应用能力。
回答思路
- 【回答框架 1】Lazy<T> 是 .NET 提供的延迟初始化容器,默认采用 ExecutionAndPublication 模式,通过内部锁或内存屏障保证多线程环境下只执行一次初始化委托,且所有线程获得同一实例。
- 【回答框架 2】当 LazyThreadSafetyMode 设为 ExecutionAndPublication 时,使用锁确保委托只执行一次,其他线程等待结果;PublicationOnly 模式则允许多个线程同时执行委托,但仅发布第一个成功的结果,适合初始化不昂贵且允许短暂竞争的场景。
- 【回答框架 3】使用方式为 new Lazy<T>(() => 初始化逻辑),通过 Value 属性触发初始化;若初始化抛异常,实例会缓存异常,后续访问继续抛出,直到成功为止。
- 【回答框架 4】适用场景包括单例模式、资源加载、昂贵对象创建等;相比 double-checked locking 手写实现,Lazy<T> 更简洁且避免易错点。
- 【回答框架 5】在不要求线程安全时可使用 LazyThreadSafetyMode.None 提升性能,但需确保单线程访问。
- 【关键点 1】Lazy<T> 默认线程安全,保证初始化委托仅执行一次。
- 【关键点 2】Value 属性触发初始化,异常会被缓存。
- 【关键点 3】ExecutionAndPublication 模式用锁避免重复初始化。
- 【关键点 4】适合实现线程安全的单例与延迟加载。
- 【关键点 5】创建成本高且并发访问频繁时优先使用 Lazy<T>。
- 【易错点 1】不要使用 None 模式进行多线程共享初始化,会导致多次初始化。
- 【易错点 2】初始化委托中若有副作用,需考虑取消机制。
- 【易错点 3】默认模式保证实例唯一,但不保证初始化顺序,若依赖顺序需额外同步。