线程安全对象 - 静态与否?

时间:2009-04-22 22:32:05

标签: .net multithreading locking

我最近在接受采访时,技术人员问我如何使应用程序保持线程安全。

好吧,在正确解释lock()之后,他说把对象当作静态不是一个好主意。

private static readonly object _syncLock = new object();

他声称原因是静态使得线程锁定的对象比非静态时更慢。这是真的吗?

编辑: 尽管如此,我仍然不确定。这三种方法有什么区别?

private static readonly object _syncLock = new object();
public static readonly object _syncLock = new object();
private readonly object _syncLock = new object();

6 个答案:

答案 0 :(得分:12)

如果锁定对象应该是静态的,则取决于要锁定的对象。如果要锁定类的实例,则不能使用静态锁定对象。如果要锁定静态数据,则无法使用实例锁定对象。所以似乎没有任何选择。

您可以考虑使用静态或实例锁定对象来锁定对实例数据的访问,但这会导致不同的行为。使用实例锁定对象时,只锁定实例,而静态锁定对象将锁定所有实例。所以在这里也无法选择性能调整。

答案 1 :(得分:7)

  

他声称原因是静态是在运行时运行而不是编译,并且会使线程锁定的对象比非静态时更慢。

这没有任何意义 - 我认为面试官不知道他在说什么,或者你误解了他的观点。

答案 2 :(得分:0)

有时在求职面试中,我会说一些我知道的不正确的事情,或者说这个候选人是否会有效地论证他的观点或者只是放弃并同意这些事情完全是胡说八道。

哦,这是关于正确使用锁的excellent article by Jeffrey Richter。 :)

答案 3 :(得分:0)

每当您需要确保同一实例不被同一个不同的线程操纵时,请使用非静态对象进行锁定。

假设你有一些List类,有一个特殊的Reorder方法,它接受一些奇怪的参数。考虑是否需要在某些并行处理过程中重新排序100个不同的列表。您只关心不同的线程不会同时操作同一个列表,因为它可能会影响您的重新排序逻辑。您不需要静态锁定,因为您在同时操作不同列表时并不在意。

具有静态锁定的方案的一个简单示例是初始化某些静态数据,您希望确保加载逻辑仅运行一次。像一些Cache或Singleton。

答案 4 :(得分:0)

如果您只有一个在多个线程之间共享的一个实例,则可以使用普通对象。但如果您有多个在多个线程之间共享的类对象,则必须使用 static 对象。

另一方面,使用普通对象,您可以管理类的一个实例的并发性,使用静态对象,您可以在所有实例的范围内管理并发性一堂课。

答案 5 :(得分:-1)

其他正确的选择使用静态实例字段取决于您需要锁定的状态(类级别或实例级别),并且锁定本身的速度没有相关差异。 但是如果您真的只需要使用实例数据,那么您的应用可以使用lock(this)运行得更快,而不是锁定所有线程访问任何实例的数据。这可能是面试官得到的 - 在一个多线程只使用实例数据的应用程序中,如果你只锁定实例,它应该确实运行得更快,因为它不会阻止其他线程使用其他实例。

相反,如果线程正在访问类级别(静态)状态,那么您需要使用单个对象将它们全部锁定。当我需要这样做时,我使用的模式是锁定类的类型:

[编辑 - 毕竟不是一个好主意,请参阅下面的评论]

lock(typeof(MyClass))
{
  // use class-level data
}

这避免了创建静态对象字段的必要性。