Пока вы обращаетесь только к экземпляру ConcurrentDictionary<>
cache
и не перезаписываете cache
новым экземпляром в одном из Profile
-методов, он является поточно-безопасным .
Из-за второго пункта лучше пометить его readonly
,
private readonly ConcurrentDictionary<int, int> cache =
new ConcurrentDictionary<int, int>();
, потому что это говорит о том, что вы можете написать этот элемент только во время создания Profile
.
РЕДАКТИРОВАТЬ: Хотя сам ConcurrentDictionary<>
является потокобезопасным, у вас все еще остается проблема неатомарности составных операций.Давайте рассмотрим два возможных метода 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()
.
EDIT2 (ответ на 2-й комментарий Чао): ConcurrentDictionary<>
имеет метод GetOrAdd()
, который принимает делегат Func<TKey, TValue>
для несуществующих значений.
void AddToCacheIfItDoesntExist(int key)
{
cache.GetOrAdd(key, SlowMethod);
}
int SlowMethod(int key)
{
Thread.Sleep(1000);
return key * 10;
}