ここでMicrosoft が提供する Double-Check Locking [Lea99] イディオムは、提供されたコードと驚くほど似ています。
マルチスレッド プログラムでは、異なるスレッドがクラスを同時にインスタンス化しようとする可能性があります。このため、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 キーワードの使用によって引き起こされる可能性があるデッドロックを回避するために、次の属性を追加して public static メソッドのみのコードを保護することを検討してください。
using System.Runtime.CompilerServices;
[MethodImpl (MethodImplOptions.Synchronized)]
public static void MySynchronizedMethod()
{
}
参考文献:
- C# クックブック (O'Reilly)、Jay Hilyard、Stephen Teilhet
- C# 3.0 デザイン パターン (O'Reilly)、Judith Bishop
- CSharp-Online.Net - シングルトン設計パターン: スレッドセーフなシングルトン