您能看出这个Double Check里的问题吗?
2009-09-02 15:11 Jeffrey Zhao 阅读(8809) 评论(96) 编辑 收藏 举报昨天在做code review时看到一位同事写了这样的代码。这段代码的目的使用Double Check的做法来保证线程安全的延迟加载。但是我看到这代码之后发现了一个问题,这个问题不是第一次出现。因此,我打算在博客上记录一笔,希望可以给更多人提个醒吧。
假设,我们有这样一个Category类型,记录的是一个树型的分类结构:
public class Category { public int CategoryID { get; set; } public List<Category> Children { get; set; } }
然后,我们需要一个CategoryLoader,提供一个Get方法从ID获得指定的Category对象:
public class CategoryLoader { private object m_mutex = new object(); private Dictionary<int, Category> m_categories; public Category GetCategory(int id) { if (this.m_categories == null) { lock (this.m_mutex) { if (this.m_categories == null) { LoadCategories(); } } } return this.m_categories[id]; } private void LoadCategories() { this.m_categories = new Dictionary<int, Category>(); this.Fill(GetCategoryRoots()); } private void Fill(IEnumerable<Category> categories) { foreach (var cat in categories) { this.m_categories.Add(cat.CategoryID, cat); Fill(cat.Children); } } private IEnumerable<Category> GetCategoryRoots() { ... } }
代码的逻辑非常简单:使用一个字典作为容器,在GetCategory方法内部使用Double Check的方式来保证线程安全(即多个线程同时访问同一个对象的GetCategory方法不会出现问题)。如果没有加载,在使用LoadCategories方法构造并填充字典。在LoadCategories方法中会获取所有的“根分类”,并调用Fill方法填充字典。Fill方法会将传入的categories集合添加到字典中,并且递归地将它们的子分类也填充至字典中。
只可惜,上面的代码有一些问题,导致Double Check没有能够实现我们预期的效果。您能看出这个问题来吗?
当然,为了演示代码的简单,我省略了很多细节。例如Category的ID缺失或有重复,Category对象不是immutable,Children属性可能会包含null,这可能都会形成问题。不过,我们就暂时不在这方面考究了吧。
晚上我会公布结果(此处)。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)