我想我已经养成了一个货物崇拜的编程习惯:
每当我需要使类线程安全时,例如具有字典或列表的类(完全封装:从不直接访问并且仅由我的类的成员方法修改),我都会创建两个对象,如下所示:
public static class Recorder {
private static readonly Object _devicesLock = new Object();
private static readonly Dictionary<String,DeviceRecordings> _devices;
static Recorder() {
_devices = new Dictionary<String,DeviceRecordings>();
WaveInCapabilities[] devices = AudioManager.GetInDevices();
foreach(WaveInCapabilities device in devices) {
_devices.Add( device.ProductName, new DeviceRecordings( device.ProductName ) );
}
}//cctor
// For now, only support a single device.
public static DeviceRecordings GetRecordings(String deviceName) {
lock( _devicesLock ) {
if( !_devices.ContainsKey( deviceName ) ) {
return null;
}
return _devices[ deviceName ];
}
}//GetRecordings
}//class
在这种情况下,我将_devices
上的所有操作包装在一个lock( _devicesLock ) {
块中。我开始怀疑这是否必要。我为什么不直接锁定字典?
在您的用例中,锁定字典会很好,因为它是私有的。您仍然需要仔细设计您的类以防止死锁。
如果字典是唯一需要线程安全的共享资源,并且代码的其他部分是线程安全的,我建议使用 ConcurrentDictionary 而不是锁定。
如果您确定主对象完全在类中使用,则不需要它。 严格来说,即使没有必要,但具有 2 变量的版本更容易推理:
- 任何阅读代码的人都不需要考虑主对象是否曾经暴露并可能被你的类之外的东西锁定
- 具有用于锁定的单独对象的代码看起来更符合良好实践
- 如果意外/故意暴露主要对象会更安全