2012-04-27 12 views
8

私はクラスがありますように、クライアントコードからアクセスし静的メソッドからの参照をスレッドセーフで戻していますか?

class PrintStringDataBuilder 
{ 
    PrintStringDataBuilder() { } 
    public static GetInstance() 
    { 
     return new PrintStringDataBuilder(); 
    } 

    //other class methods and fields, properties 
} 

PrintStringDataBuilder instance = PrintStringDataBuilder.GetInstance(); 

は、コールスレッドセーフの上ですか?

編集:書き込みを避けるだけです。 PrintStringDataBuilder builder = new PrintStringDataBuilder(); asp.net mvc web appで複数回。 PrintStringDataBuilderクラスには他の静的メソッド、静的フィールド、静的プロパティはありません。

+0

これは本当に '新しいPrintStringDataBuilder()'が何をするかによって異なります。それをシングルトンにしようとしていますか?もしそうなら、これはそうしていない。そうでなければ、コンストラクタを呼び出すだけで静的な 'GetInstance()'メソッドを持っているのはなぜですか? – cadrell0

+0

プライベートコンストラクタ 'PrintStringDataBuilder'をお持ちですか他のフィールドはどのように初期化されていますか? –

+0

なぜ落選ですか?私は良い質問だと思う。 – n8wrl

答えて

11

はい?そのクラスのコンストラクタの内部を知らなければ、GetInstance()を呼び出すことはスレッドセーフであると言うことができます。そのインスタンス上のメソッドは、スレッドセーフであることは保証されません。特に、それらのメソッドのいずれかを提示しなかったためです。

これは、単に工場パターンとして知られています。

EDIT:あなたがシングルトンを返すようにしようとしている場合、あなたはそのようにそれを行うことができます。

.NET 4+

private static Lazy<PrintStringDataBuilder> _instance = new Lazy<PrintStringDataBuilder>(() => 
    { 
     return new PrintStringDataBuilder(); 
    }); 

public static PrintStringDataBuilder GetInstance() 
{ 
    return _instance.Value; 
} 

.NET 3.5および

private static PrintStringDataBuilder _instance = null; 
private static object _lockObject = new object(); 

public static PrintStringDataBuilder GetInstance() 
{ 
    if(_instance == null) 
    { 
     lock(_lockObject) 
     { 
       if(_instance == null) 
       _instance = new PrintStringDataBuilder(); 
     } 
    } 

    return _instance; 
} 
+0

申し訳ありません、コンストラクタを書くのを忘れてしまいました。私はコードを更新しました。 – mxasim

+0

はい、コンストラクタはスレッドセーフです(何もしません)。あなたはシングルトンを返そうとしていますか? – Tejs

+0

いいえ、単にPrintStringDataBuilderの作成を避けようとしています。builder = new PrintStringDataBuilder();複数回 – mxasim

5

することにより、以下の'threadsafe'あなたは静的メソッドを呼び出す複数のスレッドが同じPrintStringDataBuilderを取得することに懸念していますか?その答えはNOで、呼び出しはスレッドセーフです。

あなたは小さなスニペットから、残りのクラスがあるかどうか、またはそのコンストラクタを誰にも伝えることはできません。クラスインスタンスがスレッドセーフではない理由はたくさんあります。それらがロックなしの静的なプロパティを参照する場合は、例です。

3

メソッドの入力は常にスレッドセーフです。共有データにアクセスすることはできません。したがって、共有データがないため、このコードはスレッドセーフです。

ここではすべてのスレッドに対して単一のインスタンスPrintStringDataBuilderを設定することをお勧めします。その場合、そのコードは機能しません。あなたは適切なシングルトンが必要です。 .NET 4のコードは非常にコンパクトにすることができる。

private static Lazy<PrintStringDataBuilder> instance = new Lazy<PrintStringDataBuilder>(); 

public static PrintStringDataBuilder Instance 
{ 
    get { return instance.Value; } 
} 

これは、すべてのスレッドでPrintStringDataBuilder.Instanceが同じを指しますとIEだけ怠惰な方法で作成されますあなたのPrintStringDataBuilderオブジェクトの唯一のインスタンスことを保証しますそれは最初に使用され、早く使用されます。

1

@Tejs、

実際、.NETにあなたがダブルチェックロック機構を使用する必要はありません - それは周りのより良い方法があります。しかし、そうすることを選択した場合、ダブルチェックロックの実装は間違っており、本当にスレッドセーフではありません。コンパイラは_instance = new PrintStringDataBuilder();の初期化を離れて最適化することができ - 3つの可能な変更は、本当にスレッドセーフあなたの例を作ることがあります。

  1. は、静的メンバをインラインで初期化する - 間違いなく最も簡単!
private static PrintStringDataBuilder _instance = new PrintStringDataBuilder; 
    public static PrintStringDataBuilder GetInstance() 
    { 
     return _instance; 
    } 

2。 'volatile'キーワードを使用して、PrintStringDataBuilderの初期化がJITによって最適化されていないことを確認してください。


private static volatile PrintStringDataBuilder _instance = null; 
private static object _lockObject = new object(); 

public static PrintStringDataBuilder GetInstance() 
{ 
    if(_instance == null) 
    { 
     lock(_lockObject) 
     { 
       if(_instance == null) 
       { 
       _instance = new PrintStringDataBuilder(); 
       } 
     } 
    } 

    return _instance; 
}

3。ダブルチェックロックを使用してInterlocked.Exchangeを使用してください。


private static PrintStringDataBuilder _instance = null; 
private static object _lockObject = new object(); 

public static PrintStringDataBuilder GetInstance() 
{ 
    if(_instance == null) 
    { 
     lock(_lockObject) 
     { 
       if(_instance == null) 
       { 
       var temp = new PrintStringDataBuilder(); 
       Interlocked.Exchange(ref _instance, temp); 
       } 
     } 
    } 

    return _instance; 
}

希望します。

関連する問題