2

デフォルトでは、非静的メソッドは、複数のスレッドを介してアクセスされる場合、スレッドごとに変数の独自のインスタンスを持っているため、パブリック変数などが含まれていない場合はスレッド セーフになります。

一方、静的メソッドの変数はスレッド間で共有され、デフォルトでは非スレッド セーフになります。

たとえば、静的変数やメソッドをまったく持たないクラスがあるとします。

public class Profile {
    private ConcurrentDictionary<int, int> cache = 
                              new ConcurrentDictionary<int, int>();

    public AddToCache() {

    }
    public RemoveToCache() {

    }
    public DoSomethingThatShouldBeThreadSafe() {

    }
}

しかし、このクラスから静的オブジェクトを作成します。

public static Profile objProfile = new Profile();

そして、複数のスレッドで objProfile にアクセスします。

問題は、プロファイル クラスのメソッド、AddToCache、RemoveFromCache、および DoSomethingThatShouldBeThreadSafe が、objProfile を介して使用されたときにスレッド セーフになるかどうかです。クラスのインスタンス全体が静的であるため、変数が静的でなくても、それらの変数はスレッド間で共有されますか?

4

3 に答える 3

8

ConcurrentDictionary<>インスタンスにのみアクセスし、メソッドのいずれかで新しいインスタンスでcache上書きしない限り、それはスレッドセーフです。cacheProfile

2点目なので、印をつけたほうがいいのでreadonly

private readonly ConcurrentDictionary<int, int> cache = 
                     new ConcurrentDictionary<int, int>();

これは、 のインスタンス化中にのみこのメンバーを書き込むことができると言っているからですProfile


編集:

それ自体ConcurrentDictionary<>はスレッドセーフですが、複合操作の非原子性の問題は依然としてあります。考えられる2 つの方法を見てみましょうGetFromCache()

int? GetFromCacheNonAtomic(int key)
{
    if (cache.ContainsKey(key))    // first access to cache
        return cache[key];         // second access to cache

    return null;
}

int? GetFromCacheAtomic(int key)
{
    int value;

    if (cache.TryGetValue(key, out value))   // single access to cache
        return value;

    return null;
}

ConcurrentDictionary<>.TryGetValue()メソッドを使用するため、2 番目のみがアトミックです。


EDIT 2(チャオの2番目のコメントへの回答):

ConcurrentDictionary<>には、存在しない値のデリゲートを取るGetOrAdd()メソッドがあります。Func<TKey, TValue>

void AddToCacheIfItDoesntExist(int key)
{
    cache.GetOrAdd(key, SlowMethod);
}

int SlowMethod(int key)
{
    Thread.Sleep(1000);
    return key * 10;
}
于 2011-06-03T09:40:05.387 に答える
1

あなたは、静的メソッドのローカル変数自体が静的であると主張しているように思えます。本当じゃない。

ローカル変数は、インスタンス メソッドと静的メソッドの両方で常にローカルであるため、変数キャプチャなどの特殊なケースを除いて、スタック上に存在します。したがって、それらはメソッドの個別の呼び出しごとにプライベートです。

于 2011-06-04T08:22:54.307 に答える
0

はい、これはスレッドセーフなセットアップである必要があります。すべての関数は、関数ローカル変数の独自の「コピー」を作成します。共有プロパティに明示的に「触れる」場合にのみ、問題が発生します。

ただし、キャッシュは 1 つしかないため、含まれているクラスを static にすると、キャッシュへのアクセスがスレッドセーフではなくなります。

于 2011-06-03T09:34:09.030 に答える