锁定String.Format()

时间:2014-04-11 09:05:05

标签: c# string locking format

我在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()是否足够?

2 个答案:

答案 0 :(得分:3)

不要锁定字符串。它们具有微妙的行为(实习,应用程序域重用,在其他位置无法预测的使用),使它们不适合这一点。如果你想要每个键锁定,创建一个字典(或类似的; Hashtable具有更好的线程语义,但是非通用的)键(字符串)来锁定对象(可能只是new object())。 / p>

答案 1 :(得分:0)

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));

因此,锁定此类字符串的一个实例将无法与另一个实例上的锁正确同步。解决这个问题的一种方法是使用String interning的.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));

另一方面,如前所述,是为每个String唯一分配一个锁定对象的单独集合。