0

即使我使用 lock 和静态 locker 对象来锁定我的代码同时访问同一个项目,我如何保证在我的 lock 期间 HttpRuntime 不会从另一个线程中删除该项目?我在 HttpRuntime 或 HttpRuntime.Cache 中看不到任何 SyncRoot 属性。

如果我指定过期回调并将我的静态储物柜对象锁定在该回调中,这样做是否合适?

在回调中锁定 HttpRuntime.Cache 过期线程是不是很糟糕?

4

2 回答 2

1

寻找“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()是线程安全的,如果它们的组合不是线程安全的,我们可能仍然需要这样做。例如,如果第一个报告对象状态并且我们根据该状态决定是否执行第二个,那么我们通常需要锁定它以防止状态在第一个和第二个方法调用之间发生变化)。

当然,对象上的所有其他操作都需要以相同的方式锁定。如果我们需要将多个对象作为一个单元进行同步,它会变得更加复杂。然后我们需要一个更复杂的规则,即我们锁定什么对象,而不是简单地锁定有问题的对象;因为没有单一的“有问题的对象”。

于 2012-08-11T18:20:26.917 回答
0

缓存是您的应用程序的私有缓存。运行时唯一对它做任何事情的时候是应用程序重新启动时(即它清除缓存)。当您将项目添加到缓存中时,如果您真的想确保没有其他任何东西干扰您的缓存,您可以提供一个回调来通知删除。

我认为最好设计应用程序和缓存中的内容,以便尽量减少访问缓存中相同项目的两件事的需要。需要两个线程来访问缓存中的同一项目表明存在设计问题。

于 2012-08-11T15:36:09.100 回答