为了最大限度地减少副作用,被锁定的对象不应该是被操作的对象,而应该是指定用于锁定的单独对象。
根据您的要求,有几种处理此问题的选项:
变体 A:私有锁定对象
如果您只是想确保DoSomething
与并行实例不冲突DoSomething
.
private static readonly object doSomethingLock = new object();
public static void DoSomething (string param1, string param2, SomeObject o)
{
//.....
lock(doSomethingLock)
{
o.Things.Add(param1);
o.Update();
// etc....
}
}
变体 B:将锁定对象作为参数传递
如果可以访问,请选择此项o
即使在外部也必须是线程安全的DoSomething
,即,如果存在其他人编写方法的可能性DoSomethingElse
它并行运行DoSomething
并且不得干扰lock
阻止DoSomething
:
public static void DoSomething (string param1, string param2, SomeObject o, object someObjectLock)
{
//.....
lock(someObjectLock)
{
o.Things.Add(param1);
o.Update();
// etc....
}
}
变体 C:创建 SyncRoot 属性
如果您可以控制实施SomeObject
,将锁定对象作为属性提供可能会很方便。这样,您就可以实现变体 B,而无需传递第二个参数:
class SomeObject
{
private readonly object syncRoot = new object();
public object SyncRoot { get { return syncRoot; } }
...
}
然后,你只需使用lock(o.SyncRoot)
in DoSomething
。这是一些 BCL 类使用的模式,例如,Array.SyncRoot http://msdn.microsoft.com/en-us/library/system.array.syncroot.aspx, ICollection.SyncRoot http://msdn.microsoft.com/en-us/library/system.collections.icollection.syncroot.aspx.