我试图通过为一些非常核心的功能引入缓存层来减轻数据库服务器的工作负担,这些功能将值插入数据库中的表并检索ID。这是在多线程环境中。

我的第一种方法是:

public class Cache {
      private Dictionary<string, Int64> i;

      public void Init() { /* init i with values from DB */ }

      public Int64 Get(string value)
         lock(i) {
            Int64 id;
            if (cache.i.TryGetValue(value, out id))
                return id;

            id = /* Insert to DB and retrieve ID */
            cache.i[value] = id;
            return id;
      }
 }

这有帮助。但是,线程彼此之间仍然等待很多。我想减少这个等待时间。我的第一个想法是使用ConcurrentDictionary.GetOrAdd(key, valueFactory)。这将不起作用,因为可以多次调用valueFactory。

我已经决定要采用这种方法:
public class Cache
{
    private ConcurrentDictionary<string, Int64> i;

    public void Init() { /* init i with values from DB */ }

    public Int64 Get(string value)
    {
        Int64 id;
        if (i.TryGetValue(value, out id))
            return id;

        lock (i)
        {
            if (i.TryGetValue(value, out id))
                return id;

            id = /* Insert to DB and retrieve ID */
            i.TryAdd(value, id);
            return id;
        }
    }

有更好的方法吗?这甚至是线程安全的吗?

最佳答案

您想要做的是延迟创建一个对象,该对象只需要创建一次即可,然后一旦创建便可以被任意数量的线程访问。 Lazy正是为此目的而设计的:

public class Cache
{
    private ConcurrentDictionary<string, Lazy<long>> i;

    public void Init() { /* init i with values from DB */ }

    public Int64 Get(string value)
    {
        return i.GetOrAdd(value, new Lazy<long>(() =>
            CreateDatabaseRecordAndGetId()))
            .Value;
    }

    private long CreateDatabaseRecordAndGetId()
    {
        throw new NotImplementedException();
    }
}

10-04 11:24