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

Raf*_*afa 24 c# multithreading

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

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

private object Locker = new object();
Run Code Online (Sandbox Code Playgroud)

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

private static object Locker = new object();
Run Code Online (Sandbox Code Playgroud)

但是这里: 为什么锁定对象必须是静态的?

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

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

谢谢!

Den*_*nis 56

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

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

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

那么,它并不必须是.这只是一种最佳做法,可以帮助您避免错误.

考虑以下代码:

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 = // ...
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这里Thread1可以获取锁定Method1,但是要执行的Thread2 Method2将忽略此锁定,因为锁定对象已更改=>状态可能已损坏.


Sea*_*ean 17

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


Kae*_*ber 11

我想这意味着"引用锁定对象的变量应该只读".

您锁定变量引用的锁定对象,而不是变量本身.即

private object Locker = new object();
Run Code Online (Sandbox Code Playgroud)

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

Locker = new object();
Run Code Online (Sandbox Code Playgroud)

并锁定它,你锁定了两个不同的对象,这违背了锁定的目的,因为你现在没有获得同步访问.


ste*_*ead 6

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

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