寻找“SyncRoot”属性建议您在将锁定与集合结合使用时使用SyncRoot 属性。这是有原因的,尽管后来的集合支持它以实现向后兼容性,但它往往通过显式实现接口而被隐藏。真的,SyncRoot 的想法不是很好。
在这种情况下,您谈论的是线程安全的集合,因此就更不需要了。 System.Web.Caching.Cache 执行自己的锁定(或其他机制,它被指定为线程安全的,而不是通过特定方法实现线程安全的),因此跨多个线程从集合中添加、访问和删除项目不会损坏它。
唯一剩下的风险是,如果对象本身不是线程安全的,或者您在同一个线程中多次从集合中访问它。
不这样做很容易避免第二个。如果你这样做:
(HttpRuntime.Cache.Get(someKey) as SomeType).SomeMethod();
(HttpRuntime.Cache.Get(someKey) as SomeType).SomeOtherMethod();
仅当您希望在第二次调用中处理与第一次不同的对象时才有意义。否则,很容易解决:
SomeType obj = HttpRuntime.Cache.Get(someKey) as SomeType;
obj.SomeMethod();
obj.SomeOtherMethod();
(通过不重复调用Get 方法,您还可以获得轻微的性能提升。
如果您需要担心不同的线程同时调用SomeMethod() 和SomeOtherMethod(),您需要确保这些方法是线程安全的,或者锁定与相关对象相关的对象。大多数时候,与对象相关的对象最明显的选择就是对象本身。因此:
SomeType obj = HttpRuntime.Cache.Get(someKey) as SomeType;
lock(obj)
{
obj.SomeMethod();
obj.SomeOtherMethod();
}
(请注意,即使SomeMethod() 和SomeOtherMethod() 是线程安全的,如果它们的组合不是线程安全的,我们可能仍然需要这样做。例如,如果第一个报告对象状态并且我们决定根据是否执行第二个,那么我们通常需要锁定它以防止第一个和第二个方法调用之间的状态发生变化。
当然,对象上的所有其他操作都需要以相同的方式锁定。如果我们需要将多个对象作为一个单元进行同步,它会变得更加复杂。然后我们需要一个更复杂的规则,即我们锁定什么对象,而不是简单地锁定有问题的对象;因为没有单一的“有问题的对象”。