この辞書がめったに書かれず、頻繁に読まれる場合、私はしばしば、書き込み時に辞書全体を置き換えることによって安全なダブルロックを採用します。これは、書き込みをまとめてバッチ処理して頻度を減らすことができる場合に特に効果的です。
たとえば、これは、型に関連付けられたスキーマオブジェクトを取得しようとするメソッドの縮小版であり、取得できない場合は、先に進んで、同じ場所で見つかったすべての型のスキーマオブジェクトを作成します。ディクショナリ全体をコピーする必要がある回数を最小限に抑えるための、指定されたタイプとしてのアセンブリ:
public static Schema GetSchema(Type type)
{
if (_schemaLookup.TryGetValue(type, out Schema schema))
return schema;
lock (_syncRoot) {
if (_schemaLookup.TryGetValue(type, out schema))
return schema;
var newLookup = new Dictionary<Type, Schema>(_schemaLookup);
foreach (var t in type.Assembly.GetTypes()) {
var newSchema = new Schema(t);
newLookup.Add(t, newSchema);
}
_schemaLookup = newLookup;
return _schemaLookup[type];
}
}
したがって、この場合のディクショナリは、スキーマを必要とするタイプのアセンブリと同じ回数だけ再構築されます。アプリケーションの残りの存続期間中、ディクショナリアクセスはロックフリーになります。ディクショナリのコピーは、アセンブリの1回限りの初期化コストになります。ポインタの書き込みはアトミックであり、参照全体が一度に切り替えられるため、ディクショナリのスワップはスレッドセーフです。
他の状況でも同様の原則を適用できます。