使用静态MemcachedClient的问题

本文关键字:问题 MemcachedClient 静态 | 更新日期: 2023-09-27 18:13:40

我使用Memcached来存储快速访问的数据。我读到创建MemcachedClient的成本很高,并且看到MemcachedClient的使用是静态的(参见:link)

所以我使用单例模式为我的客户端:

public class CommonObjectsCache
{
    private static CommonObjectsCache _cache;
    private static MemcachedClient _client;
    public static MemcachedClient Client
    {
        get
        {
            if (_client == null)
                _client = new MemcachedClient();
            return _client;
        }
        private set
        {
            _client = value;
        }
    }
    private CommonObjectsCache()
    {
        _client = new MemcachedClient();
    }
    public static CommonObjectsCache Cache
    {
        get
        {
            if (_cache == null)
                _cache = new CommonObjectsCache();
            return _cache;
        }
    }
}

在我的DAL中,我使用它们如下:

    public static List<Item1> AllItem1s
    {
        get
        {
            if (CommonObjectsCache.Client.Get<List<Item1>>("AllItem1s") == null)
                RefreshItem1Cache();
            return CommonObjectsCache.Client.Get<List<Item1>>("AllItem1s");
        }
        private set
        {
            CommonObjectsCache.Client.Store(StoreMode.Set, "AllItem1s", value);
        }
    }
    public static List<Item2> AllItem2s
    {
        get {  // Same as above }
        private set { // Same as above }
    }
    public static List<Item3> AllItem3s
    {
        get {  // Same as above }
        private set { // Same as above }
    }
    public static List<Item4> AllItem4s
    {
        get {  // Same as above }
        private set { // Same as above }
    }

并填充为:

public static void RefreshItem1Cache()
{
    List<Item1> items = (from i ctx.Item1
                        select i).ToList();
    AllItem1s = items;
}

在我的DAL代码中,我有一个方法:

public static MyModel GetMyModel(int? id)
{
    // I use AllItem1s here.
}

当我运行代码时,它有时会显示AllItem1s.Count == 0,但是当我在allitem1中放置一个断点并诊断该值时,我看到它被填充了。因此,我更新了代码,如下所示,以检查我是否做错了:

public static MyModel GetMyModel(int? id)
{
    if (AllItem1s == null || AllItem1s.Count == 0 || AllItem2s == null || AllItem2s.Count == 0 || AllItem3s == null || AllItem3s.Count == 0 || AllItem4s == null || AllItem4s.Count == 0)
    {
        string msg = "Error!!!!!";
    }
    // I use AllItem1s here.
}

和令人惊讶的是,代码落在string msg = "Error!!!!!";块!!

但是当我在if块内放置一个断点并观察每个集合的Count属性时,我看到它们有数字。

所以我得出一个结论,有一个竞争条件,而获取AllItemXs属性。当它检查条件时,至少有一个没有正确设置(这是没有意义的,因为它们在同一个线程上,属性的getter不能返回空集合)。

谁能解释一下为什么会发生这种情况以及如何克服这个问题?

使用静态MemcachedClient的问题

单例实现不是线程安全的。想象一下,两个(或更多)线程同时进行null检查:两个(所有)线程将初始化它们自己的CommonObjectsCache实例。

可以用lock语句包装null检查和初始化实例,或者使用双重检查锁定模式。

在c#中搜索线程安全的单例实现。