我正在实现asp.net mvc应用程序中的缓存,并且为了防止查询在缓存刷新时多次运行,我在任何数据库访问代码周围都使用了一个锁。
由于我对每一段数据都有一个唯一的缓存键,所以我认为锁定该字符串可能是个好主意。但有时要获取的数据对特定用户是唯一的(例如,由用户X编写的所有注释),因此我使用String.Format()将用户的id放入缓存键。
下面是一个例子:
private const string cacheKey = "blog_comments_from_specific_user-{0}";
private List<Comments> GetCommentsFromuser(int userId)
{
if (GetCache(String.Format(cacheKey, userId)) == null)
{
lock (String.Format(cacheKey, userId))
{
if (GetCache(String.Format(cacheKey, userId)) == null)
{
// get data from database
}
}
}
}我希望数据库代码只对每个唯一的字符串内容运行一次,但我不确定它是否就是这样做的。我还没有找到测试它的方法。我读到有一个String.Intern()方法,它可以锁定特定的字符串内容,但是我也需要这个方法,还是String.Format()足够了?
发布于 2014-04-11 09:12:04
不锁定字符串。他们有微妙的行为(实习,应用领域重用,不可预测的使用在其他地方),使他们不适合这一点。如果您想要按键锁定,请创建一个字典(或类似的;Hashtable具有更好的线程语义,但不是泛型的)键(字符串)来锁定对象(可能只是new object())。
发布于 2014-04-11 09:25:38
即使两个字符串匹配,String.Format也不一定返回相同的对象:
var str1 = String.Format("{0}{1}", 1, 2);
var str2 = String.Format("{0}{1}", 1, 2);
Console.WriteLine(str1 == str2);
Console.WriteLine(Object.ReferenceEquals(str1, str2));因此,锁定这样一个字符串的一个实例将不能正确地与另一个实例上的锁同步。解决这一问题的一种方法是使用.NET的串实习机制。请参见以下示例:
var str3 = String.Intern(String.Format("{0}{1}", 1, 2));
var str4 = String.Intern(String.Format("{0}{1}", 1, 2));
Console.WriteLine(str3 == str4);
Console.WriteLine(Object.ReferenceEquals(str3, str4));如前所述,另一种方法是拥有一个单独的锁对象集合,这些对象被唯一地分配给每个字符串。
https://stackoverflow.com/questions/23008128
复制相似问题