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 アプリで複数回。PrintStringDataBuilder クラスには、他の静的メソッド、静的フィールド、または静的プロパティはありません。

4

4 に答える 4

11

はい?そのクラスのコンストラクターの内部構造を知らなくても、呼び出しGetInstance()はスレッド セーフであると言えます。ただし、特にこれらのメソッドを提示しなかったため、そのインスタンスのメソッドはスレッドセーフであるとは限りません。

これは単にファクトリ パターンとして知られています。

編集:シングルトンを返そうとしている場合は、次のようにできます:

.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;
}
于 2012-04-27T17:49:54.413 に答える
5

「スレッドセーフ」によって、静的メソッドを呼び出す複数のスレッドが同じ PrintStringDataBuilder を取得することを心配していますか? それに対する答えは NO であり、呼び出しはスレッドセーフです。

そうは言っても、あなたが与えた小さなスニペットから、クラスの残りの部分がそうであるか、それともそのコンストラクターであるかは誰にもわかりません。クラス インスタンスがスレッド セーフでない理由は多数あります。ロックせずに静的プロパティを参照する場合がその例です。

于 2012-04-27T17:51:11.527 に答える
3

メソッドの入力は常にスレッドセーフです。共有データへのアクセスはそうではないかもしれません。共有データがないため、このコードはスレッドセーフです。

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

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

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

PrintStringDataBuilder.Instanceこれにより、すべてのスレッドがオブジェクトの同じインスタンスを 1 つだけ指し示すことが保証されます。PrintStringDataBuilderオブジェクトは遅延して作成されます。つまり、最初に使用されたときだけ作成されます。

于 2012-04-27T18:44:15.653 に答える
1

@ Tejs、

実際、.NETでは、ダブルチェックロックメカニズムを使用する必要はありません。これを回避するためのより良い方法があります。ただし、そうすることを選択した場合、ダブルチェックロックの実装は正しくなく、真にスレッドセーフではありません。コンパイラは初期化を最適化することができます_instance = new PrintStringDataBuilder();-あなたの例を本当にスレッドセーフにするために3つの可能な変更があります:

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

2。'volatile'キーワードを使用して、の初期化がPrintStringDataBuilderJITによって最適化されないようにします。


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;
}

お役に立てれば。

于 2013-01-16T00:11:42.843 に答える