此静态字典字段线程是否安全

本文关键字:是否 安全 线程 字段 静态 字典 | 更新日期: 2023-09-27 17:57:17

这是 Asp.net MVC Web Project。

我每 30 秒准备一次"用户树"。(刷新用户方法)所以集合操作是原子的。获取操作是多线程的。

这种方法线程安全吗?

public static class InternalCache
{
    private static Dictionary<long, UserModel> _Users;
    public static RefreshUsers(){
        //.............
        // var res=.......
        _Users= res;
    }
    public static UserModel GetUser(long id){
        return _Users[id];
    }
}

此静态字典字段线程是否安全

尽管静态变量的设置为原子变量,但您仍然面临编译器优化和指令重新排序可能导致某些线程看到_Users的过时值的风险。

要删除它,您需要在访问静态变量时使用lock或使用Interlocked函数读取/写入变量:

public static class InternalCache
{
    private static Dictionary<long, UserModel> _Users;

    public static RefreshUsers()
    {
        Interlocked.Exchange(ref _Users, res);
    }
    public static UserModel GetUser(long id)
    {            
        // Read the variable, ensuring we always see the latest value
        var users = Interlocked.CompareExchange(ref _Users, null, null);
        return users[id];            
    }
}

如果你可以确保一次只有一个线程调用你的RefreshUsers函数,那么是的,你的代码应该是线程安全的。

否则,您必须使函数线程安全:

为了使函数线程安全,您需要一个要锁定的对象:

private static object _lockObj = new Object();

然后在写入_Users时以及获取该对象时锁定该对象:

public static class InternalCache
{
    private static Dictionary<long, UserModel> _Users;
    private static object _lockObj = new Object();
    public static RefreshUsers(){
        lock (_lockObj)
        {
            //.............
            // var res=.......
            _Users= res;
        }
    }
    public static UserModel GetUser(long id){            
        return _Users[id];            
    }
}

锁确保锁块内的所有内容一次只能由一个线程访问,因为线程在到达该对象lock(...)行后立即锁定该对象。因此,当下一个线程到达此行时,他无法锁定该对象,而是等到另一个线程释放了锁。