私は 3.5 .NET Framework を使用して開発しており、アイテムの遅延読み込みパターンを使用してマルチスレッド シナリオでキャッシュを使用する必要があります。Web でいくつかの記事を読んだ後、独自の実装を作成しようとしました。
public class CacheItem
{
public void ExpensiveLoad()
{
// some expensive code
}
}
public class Cache
{
static object SynchObj = new object();
static Dictionary<string, CacheItem> Cache = new Dictionary<string, CacheItem>();
static volatile List<string> CacheKeys = new List<string>();
public CacheItem Get(string key)
{
List<string> keys = CacheKeys;
if (!keys.Contains(key))
{
lock (SynchObj)
{
keys = CacheKeys;
if (!keys.Contains(key))
{
CacheItem item = new CacheItem();
item.ExpensiveLoad();
Cache.Add(key, item);
List<string> newKeys = new List<string>(CacheKeys);
newKeys.Add(key);
CacheKeys = newKeys;
}
}
}
return Cache[key];
}
}
ご覧のとおり、Cache オブジェクトは、実際のキーと値のペアを格納するディクショナリと、キーのみを複製するリストの両方を使用します。スレッドが Get メソッドを呼び出すと、静的な共有キー リスト (volatile と宣言されている) を読み取り、Contains メソッドを呼び出して、キーが既に存在するかどうかを確認し、存在しない場合は、遅延読み込みを開始する前に二重チェックのロック パターンを使用します。読み込みの最後に、キー リストの新しいインスタンスが作成され、静的変数に格納されます。
明らかに、キーのリスト全体を再作成するコストは、単一のアイテムをロードするコストとはほとんど無関係です。
それが本当にスレッドセーフかどうか、誰かが教えてくれることを願っています。「スレッドセーフ」とは、すべてのリーダー スレッドが破損またはダーティ リードを回避でき、すべてのライター スレッドが不足しているアイテムを 1 回だけロードすることを意味します。