换句话说,这个单例实现是线程安全的:

public class Singleton
{
    private static Singleton instance;

    private Singleton() { }

    static Singleton()
    {
        instance = new Singleton();
    }

    public static Singleton Instance
    {
        get { return instance; }
    }
}

当前回答

静态构造函数将在允许任何线程访问该类之前完成运行。

    private class InitializerTest
    {
        static private int _x;
        static public string Status()
        {
            return "_x = " + _x;
        }
        static InitializerTest()
        {
            System.Diagnostics.Debug.WriteLine("InitializerTest() starting.");
            _x = 1;
            Thread.Sleep(3000);
            _x = 2;
            System.Diagnostics.Debug.WriteLine("InitializerTest() finished.");
        }
    }

    private void ClassInitializerInThread()
    {
        System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.GetHashCode() + ": ClassInitializerInThread() starting.");
        string status = InitializerTest.Status();
        System.Diagnostics.Debug.WriteLine(Thread.CurrentThread.GetHashCode() + ": ClassInitializerInThread() status = " + status);
    }

    private void classInitializerButton_Click(object sender, EventArgs e)
    {
        new Thread(ClassInitializerInThread).Start();
        new Thread(ClassInitializerInThread).Start();
        new Thread(ClassInitializerInThread).Start();
    }

上面的代码产生下面的结果。

10: ClassInitializerInThread() starting.
11: ClassInitializerInThread() starting.
12: ClassInitializerInThread() starting.
InitializerTest() starting.
InitializerTest() finished.
11: ClassInitializerInThread() status = _x = 2
The thread 0x2650 has exited with code 0 (0x0).
10: ClassInitializerInThread() status = _x = 2
The thread 0x1f50 has exited with code 0 (0x0).
12: ClassInitializerInThread() status = _x = 2
The thread 0x73c has exited with code 0 (0x0).

尽管静态构造函数运行了很长时间,但其他线程会停止并等待。所有线程都读取静态构造函数底部的_x集合的值。

其他回答

下面是上面MSDN页面上c#单例的Cliffnotes版本:

使用下面的模式,总是,你不会错:

public sealed class Singleton
{
   private static readonly Singleton instance = new Singleton();

   private Singleton(){}

   public static Singleton Instance
   {
      get 
      {
         return instance; 
      }
   }
}

除了明显的单例特性之外,它还免费提供了以下两个功能(相对于c++中的单例而言):

惰性构造(如果从未调用,则不进行构造) 同步

使用静态构造函数实际上是线程安全的。静态构造函数保证只执行一次。

来自c#语言规范:

类的静态构造函数在给定的应用程序域中最多执行一次。静态构造函数的执行由应用程序域中发生的以下事件中的第一个触发: 创建类的实例。 类的任何静态成员都被引用。

所以,是的,你可以相信你的单例会被正确地实例化。

Zooba提出了一个很好的观点(比我早15秒!),即静态构造函数不能保证线程安全的对单例对象的共享访问。这需要用另一种方式来处理。

只是为了卖弄学问,但没有静态构造函数,而是静态类型初始化器,这里有一个循环静态构造函数依赖的小演示,它说明了这一点。

静态构造函数被锁定。当类型初始化式正在运行时,任何其他试图以触发类型初始化式的方式访问该类的线程都将阻塞。

但是,运行类型初始化式的线程可以访问未初始化的静态成员。因此,如果从UI线程运行类型初始化器,请确保不要从类型初始化器调用Monitor.Enter() (lock(){})或ManualResetEventSlim.Wait()——这些是“可中断”的等待,会导致事件循环运行,在类型初始化器尚未完成时执行程序的任意其他部分。

最好使用托管块而不是非托管块。WaitHandle。WaitOne WaitHandle。WaitAny WaitHandle。WaitAll、监控。输入、监控。TryEnter,线程。加入,GC。WaitForPendingFinalizers等等都对Thread有响应。中断和线程中止。同样,如果你的线程是在一个单线程的公寓,所有这些托管阻塞操作将正确泵消息在你的公寓当你的线程被阻塞:

静态构造函数保证每个应用程序域只触发一次,所以你的方法应该是OK的。然而,它在功能上与更简洁的内联版本没有什么不同:

private static readonly Singleton instance = new Singleton();

当您在惰性初始化事物时,线程安全更是个问题。