这可能是基本问题
要在多线程环境中使用单例,我们可以使用锁。请参阅代码段。但为什么我们需要在单件模式中进行双重检查锁定?更多的是双重检查锁定意味着什么?
class singleton
{
private static singleton instance = null;
private static singleton() { }
private static object objectlock = new object();
public static singleton Instance
{
get
{
lock (objectlock) //single - check lock
{
if (instance == null)
{
instance = new singleton();
}
return instance;
}
}
}
}
答案 0 :(得分:26)
Jon Skeet explains this in detail。
锁很贵 如果对象已经存在,那么取出锁是没有意义的 因此,您可以在锁外进行第一次检查。
但是,即使在您查看之前该对象不存在,另一个线程也可能在if
条件和lock
语句之间创建它。
因此,您需要在锁内再次检查。
但是,编写单例的最佳方法是使用static
构造函数:
public sealed class Singleton
{
private Singleton()
{
}
public static Singleton Instance { get { return Nested.instance; } }
private class Nested
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested()
{
}
internal static readonly Singleton instance = new Singleton();
}
}
答案 1 :(得分:5)
使用.Net 4.x和更新版本时,您应尽可能遵循Lazy类,因为此模式与“初始化和发布”选项一起使用。 (注意:逆也可用,其中创建不是线程安全的,但实例的发布是通过Publication选项发布的)
答案 2 :(得分:3)
我所知道的“最佳”方式是:
public class MySingleton {
// object for synchronization
private static readonly object syncRoot = new object();
// the singleton instance
private static MySingleton @default;
public static MySingleton Default {
get {
// geting singleton instance without locking
var result = @default;
// if result is NOT null, no additional action is required
if ( object.ReferenceEquals(result, null) ){
// lock the synchronization object
lock(syncRoot) {
// geting singleton instanc in lock - because
// the value of @default field could be changed
result = @default;
// checking for NULL
if ( object.ReferenceEquals(result, null) ) {
// if result is NULL, create new singleton instance
result = new MySingleton();
// set the default instance
@default = result;
}
}
}
// return singleton instance
return result;
}
}
}
答案 3 :(得分:3)
多线程单例:使用双重检查锁定的最佳方法
public sealed class Singleton
{
private static volatile Singleton _instance;
private static readonly object InstanceLoker= new Object();
private Singleton() {}
public static Singleton Instance
{
get
{
if (_instance == null)
{
lock (InstanceLoker)
{
if (_instance == null)
_instance = new Singleton();
}
}
return _instance;
}
}
}
答案 4 :(得分:2)
如果您在字段初始化程序中创建对象,则不需要锁定:
class singleton
{
private static singleton instance = new singleton();
private static singleton() { }
public static singleton Instance
{
get { return instance; }
}
}
另外 - 请记住锁只是控制对象的创建,如果你在多个线程中使用它,对象仍然需要是线程安全的。
答案 5 :(得分:2)