这段代码是否锁定了函数的一部分是正确的?或者,当多个会话同时要求同一个考试时,它是否会有使用缺点?
目的是首先要求考试的客户将组装它,所有下一个客户端都将获得缓存版本。
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];
}
我觉得这不是办法。
答案 0 :(得分:5)
永远不要锁定字符串 - 它们是不可变的并且是实体的,因此当尝试在其他地方访问相同的字符串时,最终可能会锁定整个应用程序。
只需使用新的object
作为锁:
private readonly object Padlock = new object();
请参阅Tess Ferrandez撰写的this博文。
答案 1 :(得分:2)
LockString变量,它真的是一个字符串吗?你不应该锁定一个字符串,因为你可能会遇到与字符串实习有关的问题,这会导致多个锁被锁定。
另一件事是锁中似乎有很多代码,这意味着你锁定的时间比你需要的时间长。如果可以的话,尽量从锁中获取尽可能多的代码。
答案 2 :(得分:2)
它看起来基本没问题,但你不应该锁定string
。实习使得很难控制哪个实例。只需创建一个单独的对象即可锁定:
private object padLock = new object();
答案 3 :(得分:1)
你也可以使用双重检查(在考试缓存后,根本不会调用Monitor.Lock):
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];
}
}