You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何实现用于缓存的线程安全单例字典类?

线程安全的单例字典缓存实现方案

嘿,我帮你搞定这个线程安全的单例字典缓存类!这种需求在日常开发里太常见了——既要保证全局只有一个缓存实例,又得扛得住多线程同时操作的情况。直接给你上可运行的代码和详细解释吧:

完整手动锁实现版本

这个版本用经典的双重检查锁定保证单例的线程安全,同时通过手动加锁保护字典的操作:

using System;
using System.Collections.Generic;
using System.Threading;

public class ThreadSafeSingletonCache
{
    // volatile关键字确保实例状态对所有线程可见,避免指令重排序问题
    private static volatile ThreadSafeSingletonCache _instance;
    // 用于线程同步的专属锁对象
    private static readonly object _lockObj = new object();
    // 内部存储缓存的普通字典
    private readonly Dictionary<string, object> _cacheDictionary;

    // 私有构造函数,禁止外部直接实例化
    private ThreadSafeSingletonCache()
    {
        _cacheDictionary = new Dictionary<string, object>();
    }

    // 全局唯一访问入口
    public static ThreadSafeSingletonCache Instance
    {
        get
        {
            // 第一次检查,避免每次获取实例都加锁,提升性能
            if (_instance == null)
            {
                lock (_lockObj)
                {
                    // 第二次检查,确保只有第一个进入锁的线程创建实例
                    if (_instance == null)
                    {
                        _instance = new ThreadSafeSingletonCache();
                    }
                }
            }
            return _instance;
        }
    }

    // 线程安全的添加/更新缓存
    public void AddOrUpdate(string key, object value)
    {
        lock (_cacheDictionary)
        {
            if (_cacheDictionary.ContainsKey(key))
            {
                _cacheDictionary[key] = value;
            }
            else
            {
                _cacheDictionary.Add(key, value);
            }
        }
    }

    // 线程安全的获取缓存
    public bool TryGet(string key, out object value)
    {
        lock (_cacheDictionary)
        {
            return _cacheDictionary.TryGetValue(key, out value);
        }
    }

    // 线程安全的移除缓存
    public bool Remove(string key)
    {
        lock (_cacheDictionary)
        {
            return _cacheDictionary.Remove(key);
        }
    }

    // 线程安全的清空缓存
    public void Clear()
    {
        lock (_cacheDictionary)
        {
            _cacheDictionary.Clear();
        }
    }
}

// 测试用的Main方法
class Program
{
    static void Main(string[] args)
    {
        // 获取全局唯一缓存实例
        var cache = ThreadSafeSingletonCache.Instance;

        // 添加缓存项
        cache.AddOrUpdate("User:1", new { Id = 1, Name = "Alice" });
        cache.AddOrUpdate("Product:100", new { Id = 100, Price = 99.99 });

        // 获取并输出缓存项
        if (cache.TryGet("User:1", out var user))
        {
            Console.WriteLine($"获取到用户信息: {user}");
        }

        // 移除指定缓存项
        cache.Remove("Product:100");

        // 清空所有缓存
        cache.Clear();
    }
}

关键设计细节

  • 双重检查锁定:这是线程安全单例的经典实现,既保证了全局唯一实例,又避免了每次获取实例都加锁的性能开销。volatile关键字是关键,它能防止CPU指令重排序导致的多线程下实例未完全初始化就被访问的问题。
  • 字典线程安全保护:.NET自带的Dictionary<TKey,TValue>本身不是线程安全的,所以我们对所有字典操作都加了锁,确保同一时间只有一个线程能修改或读取字典。

简化版本(使用ConcurrentDictionary)

如果你的项目基于.NET Framework 4.0+或.NET Core,推荐直接用ConcurrentDictionaryLazy<T>来实现,代码更简洁,性能也更优:

using System;
using System.Collections.Concurrent;

public class ThreadSafeSingletonCache
{
    // Lazy<T>自带线程安全的延迟初始化,无需手动加锁
    private static readonly Lazy<ThreadSafeSingletonCache> _lazyInstance = new Lazy<ThreadSafeSingletonCache>(() => new ThreadSafeSingletonCache());
    // 内置线程安全的字典
    private readonly ConcurrentDictionary<string, object> _cacheDictionary;

    private ThreadSafeSingletonCache()
    {
        _cacheDictionary = new ConcurrentDictionary<string, object>();
    }

    public static ThreadSafeSingletonCache Instance => _lazyInstance.Value;

    public void AddOrUpdate(string key, object value)
    {
        // ConcurrentDictionary自带线程安全的增改方法
        _cacheDictionary.AddOrUpdate(key, value, (existingKey, existingValue) => value);
    }

    public bool TryGet(string key, out object value)
    {
        return _cacheDictionary.TryGetValue(key, out value);
    }

    public bool Remove(string key)
    {
        return _cacheDictionary.TryRemove(key, out _);
    }

    public void Clear()
    {
        _cacheDictionary.Clear();
    }
}

这个版本里,Lazy<T>帮我们处理了单例的线程安全初始化,ConcurrentDictionary则内置了所有线程安全的操作方法,省去了手动加锁的麻烦,高并发场景下表现更好。

内容的提问来源于stack exchange,提问作者Ku ttan

火山引擎 最新活动