如果这本字典很少写而且经常读,那么我经常通过在写时替换整个字典来使用安全双重锁定。如果您可以一起批量写入以降低它们的频率,这将特别有效。
例如,这是我们使用的方法的简化版本,它试图获取与类型关联的模式对象,如果不能,则继续为在同一类型中找到的所有类型创建模式对象将程序集作为指定类型以最小化必须复制整个字典的次数:
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];
}
}
因此,在这种情况下,字典最多将被重建,其次数与具有需要模式的类型的程序集一样多。在应用程序生命周期的剩余时间里,字典访问将是无锁的。字典副本成为程序集的一次性初始化成本。字典交换是线程安全的,因为指针写入是原子的,因此整个引用会立即切换。
您也可以在其他情况下应用类似的原则。