静态初始化保证单线程安全?(C#)
可能重复:静态初始化保证单线程安全?(C#),c#,constructor,singleton,multithreading,C#,Constructor,Singleton,Multithreading,可能重复: Jon Skeet的优秀文章at和我读过的其他文章清楚地表明,双重检查锁定在C#和Java中都不起作用,除非有人显式地将实例标记为“volatile”。如果没有,将其与null进行比较的检查可能会返回false,即使实例构造函数尚未完成运行。在Skeet先生的第三个示例中,他清楚地说明了这一点:“Java内存模型不能确保在将对新对象的引用分配给实例之前完成构造函数。Java内存模型在版本1.5中进行了重新设计,但在没有易失性变量的情况下(如C#),双重检查锁定仍然被破坏。” 然而,
Jon Skeet的优秀文章at和我读过的其他文章清楚地表明,双重检查锁定在C#和Java中都不起作用,除非有人显式地将实例标记为“volatile”。如果没有,将其与null进行比较的检查可能会返回false,即使实例构造函数尚未完成运行。在Skeet先生的第三个示例中,他清楚地说明了这一点:“Java内存模型不能确保在将对新对象的引用分配给实例之前完成构造函数。Java内存模型在版本1.5中进行了重新设计,但在没有易失性变量的情况下(如C#),双重检查锁定仍然被破坏。” 然而,大多数人都同意(包括Skeet先生,在他的文章的示例4和示例5中),使用静态初始化是获取线程安全单例实例的简单方法。他指出,“C#中的静态构造函数被指定为仅在创建类实例或引用静态成员时执行,并且每个AppDomain仅执行一次。” 这是有道理的,但似乎缺少的是保证只有在构造函数完成后才分配对新对象的引用——否则我们会遇到同样的问题,导致双重检查锁定失败,除非您将实例标记为volatile。当使用静态初始化来调用实例构造函数时(与从属性的get{}调用实例构造函数不同,就像我们使用双重检查锁定一样),是否可以保证构造函数将在任何其他线程获得对对象的引用之前完全完成
谢谢 是;声明中保证它只在每个AppDomain中执行一次 只有当它可以执行多次时才可能是不安全的;如前所述,它不能,所以一切都很好:) 构造函数将在任何其他线程获得对该对象的引用之前完全完成 每个
AppDomain
,静态初始值设定项将仅被调用一次(至少由系统调用),并以同步方式调用,同时考虑“beforefieldinit”。因此,假设您没有做任何奇怪的事情,在静态初始值设定项中指定的任何静态字段都应该可以;任何其他使用静态字段的尝试都应该被静态构造函数阻止
对新对象的引用仅在构造函数完成后分配
事情发生的时候就发生了。例如,任何静态字段初始值设定项都发生在您通常认为的构造函数之前。但是由于其他线程被阻塞,这不应该是一个问题
然而:
- 如果静态初始值设定项本身将引用传递到外部(通过调用引用作为参数的方法(包括“arg0”),则所有赌注都将被取消
- 如果您使用反射来调用静态构造函数(是的,您可以这样做),疯狂通常会随之而来