2

这是场景:

  • 线程 A 询问所有法语书籍

  • 线程 B 询问所有阿拉伯语书籍

如果线程 A 在锁定区域内,线程 B 将在锁定区域外等待线程 A 完成。

因为代码中只有一个“地方”可以让线程 B 获取他的数据。

我想根据缓存中的密钥进行锁定,这意味着:

if(Cache["BooksInFrench"] == null)
{
    lock("BooksInFrench")
    {
        if(Cache["BooksInFrench"] == null)
        {
        object d = GetFromDB();
        cache["BooksInFrench"] = d;
        }
}

BooksInArabic 等也是如此......所以这样,如果我有 200 个连接到我的网站,其中 10 个请求 BooksInFrench,其余的请求(BooksInArabic,BooksInHebrew......)可以运行并获取他们的数据因为他们的请求不在锁定区域。

我当前的代码如下所示: http: //pastebin.com/LFhxgHDM

我认为双重锁定不是很好......你看到任何其他解决方案/改进吗?

4

1 回答 1

0

它可能只是在您的示例伪代码中,但建议在字符串上锁定对象(因为较低级别的优化,如不可变共享字符串、规范版本等 - 请参阅按字符串锁定。这安全/合理吗?)。

对于一个已知的lock

// In your class
private static readonly object BooksInFrenchLock= new object();
private const string BookInFrenchCacheKey = "BooksInFrench";

// In your cache block
if(Cache[BookInFrenchCacheKey] == null)
{
    lock(BooksInFrenchLock)
    {
        if(Cache[BookInFrenchCacheKey] == null)
        {
            object d = GetFromDB();
            Cache[BookInFrenchCacheKey] = d;
        }
}

为了从数据库中锁定多个对象,您可以使用 aConcurrentDictionary而不是哈希表(如您的 pastebin 代码中所示) - 它将使您免于一个额外的“级别”锁定。魔术发生在BookLocks.GetOrAdd(bookLanguage, s => new object()).

// In your class
private static readonly ConcurrentDictionary<string, object> BookLocks =
    new ConcurrentDictionary<string, object>();

// In your cache block
string bookLanguage = formatAndCleanBookLanguageArgument();

if(Cache[bookLanguage] == null)
{
    object lockObject = BookLocks.GetOrAdd(bookLanguage, s => new object());

    lock(lockObject)
    {
        if(Cache[bookLanguage] == null)
        {
            object d = GetFromDB();
            Cache[bookLanguage] = d;
        }
}
于 2012-08-15T18:24:52.600 回答