Microsoft在此处提供的 Double-Check Locking [Lea99] 习语与您提供的代码惊人地相似,不幸的是,这不符合 ECMA CLI 标准,即线程安全代码的清教徒视图,并且可能无法在所有情况下正常工作。
在多线程程序中,不同的线程可以尝试同时实例化一个类。出于这个原因,依赖 if 语句来检查实例是否为 null 的 Singleton 实现将不是线程安全的。不要写这样的代码!
创建线程安全单例的一种简单但有效的方法是使用嵌套类来实例化它。以下是惰性实例化单例的示例:
public sealed class Singleton
{
private Singleton() { }
public static Singleton Instance
{
get
{
return SingletonCreator.instance;
}
}
private class SingletonCreator
{
static SingletonCreator() { }
internal static readonly Singleton instance = new Singleton();
}
}
用法:
Singleton s1 = Singleton.Instance;
Singleton s2 = Singleton.Instance;
if (s1.Equals(s2))
{
Console.WriteLine("Thread-Safe Singleton objects are the same");
}
通用解决方案:
public class Singleton<T>
where T : class, new()
{
private Singleton() { }
public static T Instance
{
get
{
return SingletonCreator.instance;
}
}
private class SingletonCreator
{
static SingletonCreator() { }
internal static readonly T instance = new T();
}
}
用法:
class TestClass { }
Singleton s1 = Singleton<TestClass>.Instance;
Singleton s2 = Singleton<TestClass>.Instance;
if (s1.Equals(s2))
{
Console.WriteLine("Thread-Safe Generic Singleton objects are the same");
}
最后,这里有一个相关且有用的建议 - 为了帮助避免使用 lock 关键字可能导致的死锁,请考虑添加以下属性以帮助保护仅公共静态方法中的代码:
using System.Runtime.CompilerServices;
[MethodImpl (MethodImplOptions.Synchronized)]
public static void MySynchronizedMethod()
{
}
参考:
- C# Cookbook (O'Reilly)、Jay Hilyard 和 Stephen Teilhet
- C# 3.0 设计模式 (O'Reilly),Judith Bishop
- CSharp-Online.Net - 单例设计模式:线程安全的单例