C#静态类私有字段是否安全?

Yev*_*nat 7 c# static multithreading private class

我有一个从多个线程访问的C#静态类.两个问题:

  1. 在声明初始化字段时,我的私有静态字段是否安全?
  2. 从静态构造函数中创建私有静态字段时,我应该锁定吗?

使用来自不同线程的静态类:

class Program
    {
        static void Main(string[] args)
        {
            for (int i = 0; i < 100; i++)
            {
                Task.Run(() =>
                {
                    string name = MyStaticClass.GetValue(9555);
                    //...
                });
            }
        }
}
Run Code Online (Sandbox Code Playgroud)

静态类的选项1:

public static class MyStaticClass
    {
        private static MyClass _myClass = new MyClass();

        public static string GetValue(int key)
        {
            return _myClass.GetValue(key);
        }
    }
Run Code Online (Sandbox Code Playgroud)

静态类的选项2:

public static class MyStaticClass
    {
        private static MyClass _myClass;
        private static object _lockObj = new object();

        static MyStaticClass()
        {
            InitMyClass();
        }

        private static void InitMyClass()
        {
            if (_myClass == null)
            {
                lock(_lockObj)
                {
                    if (_myClass == null)
                    {
                        _myClass = new MyClass();
                    }
                }
            }
        }

        public static string GetValue(int key)
        {
            return _myClass.GetValue(key);
        }
    }
Run Code Online (Sandbox Code Playgroud)

从静态类创建的实例类:

public class MyClass
    {
        private Dictionary<int, Guid> _valuesDict = new Dictionary<int, Guid>();

        public MyClass()
        {
            for (int i = 0; i < 10000; i++)
            {
                _valuesDict.Add(i, Guid.NewGuid());
            }
        }

        public string GetValue(int key)
        {
            if (_valuesDict.TryGetValue(key, out Guid value))
            {
                return value.ToString();
            }

            return string.Empty;
        }
    }
Run Code Online (Sandbox Code Playgroud)

Eri*_*ert 14

从静态构造函数中初始化私有静态字段时,我应该锁定吗?

我们不要在这里埋葬lede:

永远不要锁定静态构造函数.静态构造函数已被框架锁定,因此它们只在一个线程上运行一次.

这是一个更普遍的好建议的特例:永远不要对静态构造函数中的线程做任何想象.静态构造函数被有效锁定的事实,以及任何访问您的类型的代码都可以对锁进行争议,这意味着您可以非常快速地陷入您不期望并且很难看到的死锁.我在这里举个例子:https://ericlippert.com/2013/01/31/the-no-lock-deadlock/

如果你想要延迟初始化,请使用Lazy<T>构造; 它是由知道如何使其安全的专家撰写的.

在声明初始化字段时,我的私有静态字段是否安全?

线程安全性是在从多个线程调用程序元素时保留程序不变量.你没有说过你的不变量,所以不可能说你的程序是否"安全".

如果您担心的不变量是静态构造函数在执行第一个静态方法之前运行,或者创建了第一个类型的实例,则C#保证这一点.当然,如果你在静态构造函数中编写疯狂的代码,那么疯狂的事情就会发生,所以再次尝试保持静态构造函数非常简单.