ThreadStatic的C#Singleton模式设计

luc*_*cky 5 c# singleton multithreading singleton-methods threadstatic

我想弄清楚单身模式设计.我想从我的单例类为每个线程创建单独的实例.所以我在下面提供了两个设计.

这是工作

class Program
{
    static void Main(string[] args)
    {
        Task.Factory.StartNew(() => Console.WriteLine(SingletonClass.Instance.GetHashCode()));
        Task.Factory.StartNew(() => Console.WriteLine(SingletonClass.Instance.GetHashCode()));
        Console.ReadLine();
    }
}
public sealed class SingletonClass
{
    [ThreadStatic]
    private static SingletonClass _instance;

    public static SingletonClass Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new SingletonClass();
            }
            return _instance;
        }
    }
    private SingletonClass()
    {

    }
}
Run Code Online (Sandbox Code Playgroud)

它不起作用(抛出NullReferenceException并且没有创建实例.)

class Program
{
    static void Main(string[] args)
    {
        Task.Factory.StartNew(() => Console.WriteLine(SingletonClass.Instance.GetHashCode()));
        Task.Factory.StartNew(() => Console.WriteLine(SingletonClass.Instance.GetHashCode()));
        Console.ReadLine();
    }
}
public sealed class SingletonClass
{
    [ThreadStatic]
    private static SingletonClass _instance = new SingletonClass();

    public static SingletonClass Instance
    {
        get
        {
            return _instance;
        }
    }
    private SingletonClass()
    {

    }
}
Run Code Online (Sandbox Code Playgroud)

我真的很想知道为什么没有为第二个设计创建实例.请问有人解释一下吗?

Luc*_*hin 3

您问题的答案主要与类字段的初始化方式有关。

在第二个示例中,该_instance字段在声明时初始化。每次在声明时初始化静态字段时,都会创建一个静态构造函数(如果尚未声明它)。在编译时,初始化将被移至静态构造函数中。这意味着你最终会得到这样的结果(没有复制 IL 代码,因为它会更难理解):

public sealed class SingletonClass
{
    [ThreadStatic]
    private static SingletonClass _instance;

    public static SingletonClass Instance
    {
        get
        {
            return _instance;
        }
    }
    static SingletonClass()
    {
        _instance = new SingletonClass();
    }
}
Run Code Online (Sandbox Code Playgroud)

CLR 确保静态构造函数仅被调用一次,无论您有多少个线程。查看上面的代码,这意味着对于您创建的两个任务,该_instance字段只会初始化一次(因为只会调用一次静态构造函数)。