c# - 锁定非静态字段有什么问题?锁定特定实例的正确方法是什么?

标签 c# multithreading locking thread-safety deadlock

为什么锁定非静态字段被认为是不好的做法?

而且,如果我不锁定非静态字段,那么如何在不锁定同一类或派生类的所有其他实例上的方法的情况下锁定实例方法?

我写了一个例子来让我的问题更清楚。

public abstract class BaseClass
{

    private readonly object NonStaticLockObject = new object();
    private static readonly object StaticLockObject = new object();

    protected void DoThreadSafeAction<T>(Action<T> action)
        where T: BaseClass
    {
        var derived = this as T;
        if(derived == null)
        {
            throw new Exception();
        }
        lock(NonStaticLockObject)
        {
            action(derived);
        }
    }
}
public class DerivedClass :BaseClass
{
    private readonly Queue<object> _queue;
    public void Enqueue(object obj)
    {
        DoThreadSafeAction<DerivedClass>(x=>x._queue.Enqueue(obj));
    }
}

如果我在 StaticLockObject 上进行锁定,那么 DoThreadSafeAction 方法将为从 BaseClass 派生的所有类的所有实例锁定那不是我想要的。我想确保没有其他线程可以在锁定对象的特定实例上调用方法。

更新

谢谢大家的帮助:我已经发布了另一个问题作为对你们提供的一些信息的跟进。由于您似乎精通该领域,因此我发布了链接:What is wrong with this solution to locking and managing locked exceptions?

最佳答案

这不是坏习惯,而是你的目的是什么。

静态字段可访问(或“通用”)该类型的所有实例。因此,锁定此类静态字段使您能够控制该类型的所有实例之间的并发性,或者,实现的并发控制范围是该类型的所有实例。

但是,如果您锁定一个非静态字段,该锁定将仅对该实例有效,因此您仅在该实例内控制并发,或者并发控制的范围实现就是实例。


现在,每当锁定一个对象时,我都会这样做。我同意的资源是什么?也许它是数据库,也许它是一堆在我进行特定处理时无法更改的实例字段,等等。一旦我知道我将自己锁定在外面的是什么,我就会检查它的范围。

  1. 如果它是我的应用程序之外的实体,那么它就是应用程序范围。所有东西都必须同时上锁。
  2. 如果它是一堆实例字段,那么它就是实例范围。
  3. 如果它是一堆静态字段,那么它就是类型范围。

因此,对于 1 和 3,使用静态字段。对于 2,使用实例字段。

现在,另一件事:通常,对于 1,您将有一个环绕该资源的类。而且,通常您会将该类设计为 singleton .现在,对于单例,这很有趣:根据设计,您可以保证只有一个实例,因此无论您是锁定实例还是锁定静态字段都没有关系。

PS.:如果是用锁来保护单例的实例化,当然应该是静态的。 (为什么?)

关于c# - 锁定非静态字段有什么问题?锁定特定实例的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4978791/

相关文章:

c# - HTTP 错误 500.19 - 无法读取配置文件

c# - 从 .net(C#) 中的 Webbrowser 控件检索选定的文本

c - 为什么更多的线程需要更多的时间来处理?

java - 多线程环境下使用哪些Java集合类比较好

c# - 使用 lock 语句在 C# 中递归/嵌套锁定

c# - WPF 安装部署项目

c# - C# 中的 DateTime.MinValue 与 new DateTime()

c - 如何只初始化一次信号量?

linux - Linux 线程中的文件段/节/记录锁

java - 信号能保证到达线程吗?