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

时间:2021-10-15 20:59:53

I was recently in an interview and the tech guy asked me about how to make an application thread-safe.

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

Well, after explaining the lock() correctly, he said it is not a good idea to have the object as static.

好吧,在正确解释了lock()之后,他说将对象设置为静态并不是一个好主意。

private static readonly object _syncLock = new object();

He claimed the reason is that static makes that object slower for threads to lock than if it was non static. Is this true?

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

EDIT: Nonetheless I am still not sure. What is the difference between these three approaches?

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

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

6 个解决方案

#1


If a lock object should be static or not depends on the object you want to lock. If you want to lock an instance of a class you cannot use a static lock object. If you want to lock static data you cannot use an instance lock object. So there seems not to be any choice.

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

You could think about using a static or an instance lock object to lock the access to instance data, but this results in different behaviors. With an instance lock object you lock only an instance while an static lock object will lock all instances. So no choice for performance tuning here, too.

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

#2


He claimed the reason is that static is run at runtime instead of compilation and would make that object slower for threads to lock than if it was non static.

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

This doesn't really make any sense - I think either the interviewer did not know what he was talking about, or maybe you misunderstood his point.

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

#3


Sometimes in job interviews I say something I know is incorrect or something that is utter nonsense to see if the candidate will effectively argue his point or just give up and agree.

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

Oh and here's an excellent article by Jeffrey Richter on the proper uses of lock. :)

哦,这是杰弗里里希特关于正确使用锁的一篇优秀文章。 :)

#4


Use a non static object for the lock whenever you need to make sure the same instance isn't manipulated by different threads at the same time.

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

Lets say you have some List classes, with a special Reorder method that accepts some strange arguments. Consider if you need to reorder 100 different lists during some paralel processes. You only care that different threads don't manipulate the same list at the same time, as it might affect your reorder logic. You don't need a static lock, as you don't care when different lists are being manipulated at the same time.

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

A simple example of a scenario with a static lock, is initialization of some static data, where you want to make sure the load logic is ran only once. Like some Cache or a Singleton.

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

#5


If you have only one instance of a class that shares between multiple threads, it's ok to use normal object. but if you have multiple objects of a class that share between multiple threads, you have to use static object.

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

On the other hand, with normal object you can manage concurrency for one instance of a class and with static object you can manage concurrency in the scope of all instances of a class.

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

#6


The others are correct that the choice of using a static of instance field depends on what state (class-level or instance-level) that you need to lock, and there is no relevant difference in speed for the lock itself. BUT if you really only need to use instance data then your app could run much faster using lock(this) rather than locking out all threads from accessing the data of ANY instance. That might have been what the interviewer was getting at - in an application where multiple threads are only using instance data it should indeed run faster if you only lock the instance because it won't block other threads from using other instances.

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

Conversely if threads are accessing class-level (static) state then you need to lock them all with a single object. When I need to do this, a pattern I've used is to lock the type of the class like this:

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

[Edit - not such a good idea after all, see comments below]

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

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

This avoids the necessity of creating the static object field.

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

#1


If a lock object should be static or not depends on the object you want to lock. If you want to lock an instance of a class you cannot use a static lock object. If you want to lock static data you cannot use an instance lock object. So there seems not to be any choice.

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

You could think about using a static or an instance lock object to lock the access to instance data, but this results in different behaviors. With an instance lock object you lock only an instance while an static lock object will lock all instances. So no choice for performance tuning here, too.

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

#2


He claimed the reason is that static is run at runtime instead of compilation and would make that object slower for threads to lock than if it was non static.

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

This doesn't really make any sense - I think either the interviewer did not know what he was talking about, or maybe you misunderstood his point.

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

#3


Sometimes in job interviews I say something I know is incorrect or something that is utter nonsense to see if the candidate will effectively argue his point or just give up and agree.

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

Oh and here's an excellent article by Jeffrey Richter on the proper uses of lock. :)

哦,这是杰弗里里希特关于正确使用锁的一篇优秀文章。 :)

#4


Use a non static object for the lock whenever you need to make sure the same instance isn't manipulated by different threads at the same time.

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

Lets say you have some List classes, with a special Reorder method that accepts some strange arguments. Consider if you need to reorder 100 different lists during some paralel processes. You only care that different threads don't manipulate the same list at the same time, as it might affect your reorder logic. You don't need a static lock, as you don't care when different lists are being manipulated at the same time.

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

A simple example of a scenario with a static lock, is initialization of some static data, where you want to make sure the load logic is ran only once. Like some Cache or a Singleton.

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

#5


If you have only one instance of a class that shares between multiple threads, it's ok to use normal object. but if you have multiple objects of a class that share between multiple threads, you have to use static object.

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

On the other hand, with normal object you can manage concurrency for one instance of a class and with static object you can manage concurrency in the scope of all instances of a class.

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

#6


The others are correct that the choice of using a static of instance field depends on what state (class-level or instance-level) that you need to lock, and there is no relevant difference in speed for the lock itself. BUT if you really only need to use instance data then your app could run much faster using lock(this) rather than locking out all threads from accessing the data of ANY instance. That might have been what the interviewer was getting at - in an application where multiple threads are only using instance data it should indeed run faster if you only lock the instance because it won't block other threads from using other instances.

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

Conversely if threads are accessing class-level (static) state then you need to lock them all with a single object. When I need to do this, a pattern I've used is to lock the type of the class like this:

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

[Edit - not such a good idea after all, see comments below]

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

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

This avoids the necessity of creating the static object field.

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