为什么锁定对象必须是只读的?

时间:2014-02-27 08:42:10

标签: c# multithreading

实现锁定时,我曾经在我的类中创建一个私有对象:

如果我想确保它在创建我的类的线程中被锁定:

private object Locker = new object();

如果我想确保它将被我的应用程序中的所有线程锁定:

private static object Locker = new object();

但是在这里: Why does the lock object have to be static?

在许多其他问题中,每个人都说对象必须是readonly。我没有找到原因 - 即使在MSDN或JavaDoc中也没有。

由于我经常使用这种结构,有人可以向我解释为什么要使用readonly

谢谢!

4 个答案:

答案 0 :(得分:53)

  

如果我想确定它将被锁定在我的所有线程中   应用程序:

如果锁定对象锁定对静态的访问权限,则该锁定对象必须是静态的 否则它必须是实例,因为不需要锁定一个类实例的状态,并阻止其他线程同时使用另一个类实例。

  

每个人都说对象必须是“只读”我没有找到   原因

嗯,它不是必须。这只是一种最佳做法,可以帮助您避免错误。

考虑以下代码:

class MyClass
{
    private object myLock = new object();
    private int state;

    public void Method1()
    {
        lock (myLock)
        {
            state = // ...
        }
    }

    public void Method2()
    {
        myLock = new object();
        lock (myLock)
        {
            state = // ...
        }
    }
}

这里Thread1可以通过Method1获取锁定,但是要执行Method2的Thread2将忽略此锁定,因为锁定对象已被更改=>国家可能已被腐败。

答案 1 :(得分:17)

它不必是只读的,但这是一个很好的做法,因为它可以避免意外更换它,这可能导致一些难以追踪的错误。

答案 2 :(得分:11)

我想这意味着“引用锁定对象的变量应该只读”。

锁定变量引用的锁定对象,而不是变量本身。即具有

private object Locker = new object();

你锁定了那个新对象(),而不是Locker字段。然后,如果您使用对另一个对象的引用替换该字段的值,请说

Locker = new object();

并锁定它,你锁定两个不同的对象,这就失去了锁定的目的,因为你现在没有获得同步访问。

答案 3 :(得分:6)

理想情况下,对象应该是只读的,以便不能将其更改为指向另一个对象。如果您对一个对象进行了锁定,那么另一个线程会更改该对象,如果,然后另一个线程出现,并尝试对该对象进行锁定,则该对象将不相同,因此原始锁定将是无效。

这将是一个非常罕见的情况。但是如果你对对象有一个锁定,而另一个线程在那个对象上等待,如果锁定线程调用Monitor.Pulse,则等待的线程被唤醒,并且可以对该对象进行锁定。在被唤醒和获取锁定之间的那段时间内,另一个线程可以更改锁中引用的对象,因此等待的线程将锁定另一个对象。