Asp.net C#.NET中函数锁定部分的复查

Asp.net C#.NET中函数锁定部分的复查,asp.net,caching,Asp.net,Caching,我锁定函数一部分的这段代码正确吗?或者当多个会话同时要求同一个考试时,它会有使用缺陷吗 其目的是,第一个请求检查的客户端将组装它,所有下一个客户端将获得缓存版本 public Exam GetExamByExamDto(ExamDTO examDto, int languageId) { Log.Warn("GetExamByExamDto"); lock (LockString) { if (!ContainsExam(examDto.id, langu

我锁定函数一部分的这段代码正确吗?或者当多个会话同时要求同一个考试时,它会有使用缺陷吗

其目的是,第一个请求检查的客户端将组装它,所有下一个客户端将获得缓存版本

public Exam GetExamByExamDto(ExamDTO examDto, int languageId)
{
    Log.Warn("GetExamByExamDto");
    lock (LockString)
    {
        if (!ContainsExam(examDto.id, languageId))
        {
            Log.Warn("Assembling ExamDto");
            var examAssembler = new ExamAssembler();
            var exam = examAssembler.createExam(examDto);

            if (AddToCache(exam))
            {
                _examDictionary.Add(examDto.id + "_" + languageId, exam);
            }
            Log.Warn("Returning non cached ExamDto");
            return exam;
        }
    }
    Log.Warn("Returning cached ExamDto");
    return _examDictionary[examDto.id + "_" + languageId];
}

我觉得这不是解决问题的方法。

永远不要锁定字符串-它们是不可变的,并且是固定的,因此当尝试在其他地方访问相同的字符串时,您可能会锁定整个应用程序

只需使用新的
对象
作为锁定:

private readonly object Padlock = new object();

请参阅Tess Ferrandez的博文。

LockString变量,它真的是字符串吗?您不应该锁定一个字符串,因为您可能最终会遇到与字符串实习相关的问题,这将导致多个锁被锁定


另一件事是,锁中似乎有很多代码,这意味着你锁的时间比你可能不得不锁的时间长。如果可以,尝试从锁中取出尽可能多的代码。

看起来基本上没问题,但不应该锁定
字符串。实习使得很难控制哪个实例是哪个实例。只需创建一个单独的对象来锁定:

 private object padLock = new object();

此外,您还可以使用双重检查(在缓存检查后,监视器将不会调用锁):


安德鲁,我现在用你的调整来检查性能。啊,我们只是在调查你的代码有问题。这可能不是线程安全的。@Lieven,不过,这是优化,除非你真的有速度问题,否则我会还原到你的原始代码。双重检查锁定经常被证明是被破坏的。@Henk,你能给出这样的检查何时会被破坏的例子吗?下面是Java的链接,在.NET中它取决于内存模型等。
public Exam GetExamByExamDto(ExamDTO examDto, int languageId)
{
    Log.Warn("GetExamByExamDto");
    if (!ContainsExam(examDto.id, languageId))
    {
        lock (LockString) // Here should be some private locking object.
        {
            if (!ContainsExam(examDto.id, languageId))
            {
                Log.Warn("Assembling ExamDto");
                var examAssembler = new ExamAssembler();
                var exam = examAssembler.createExam(examDto);

                if (AddToCache(exam))
                {
                    _examDictionary.Add(examDto.id + "_" + languageId, exam);
                }
                Log.Warn("Returning non cached ExamDto");
                return exam;
            }
        }
        Log.Warn("Returning cached ExamDto");
        return _examDictionary[examDto.id + "_" + languageId];
    }
}