3

当某些线程锁定并myListSomeMethodA执行内部块lock时,其他线程是否可以执行或者它会因为'myList'被锁定而myList.Add(1)等待?SomeMethodBSomeMethodA

class A
{
    private List<int> myList;

    public void SomeMethodA()
    {
       lock(myList)
       {
          //...
       }
    }

    public void SomeMethodB()
    {
       myList.Add(1);
    }
}
4

4 回答 4

6

编辑明确回答:,您需要在SomeMethodB. 编译器不会自动为你加锁

  • 为什么你必须明确锁定否则?
  • 事情会非常缓慢。仅仅禁止多线程比总是锁定每个对象访问要好得多1

推荐的成语是这样的:

class A
{
    private List<int> myList;
    private readonly object _lockObject = new Object();

    public void SomeMethodA()
    {
       lock(_lockObject)
       {
          //...
       }
    }

    public void SomeMethodB()
    {
       lock(_lockObject)
       {
           myList.Add(1);
       }
    }
}

小心暴露像这样的细粒度锁定(只要锁定下不会发生阻塞操作,您通常希望进行粗粒度锁定)。

注意C# 中的锁是可重入的,因此 SomeMethodB从锁中调用SomeMethodA不会死锁

使用私有锁object实例更新背后的基本原理:

通常,避免锁定公共类型或超出代码控制范围的实例。常见的构造 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 违反了此准则:

  • lock (this)如果实例可以公开访问,则存在问题。
  • lock (typeof (MyType))如果MyType可以公开访问是一个问题。
  • lock("myLock")这是一个问题,因为进程中使用相同字符串的任何其他代码都将共享相同的锁。

最佳实践是定义一个私有对象来锁定,或者一个私有静态对象变量来保护所有实例共有的数据。

请参阅:http: //msdn.microsoft.com/en-us/library/c5kehkcz.aspx


1(除了该方法的其他问题,例如空值、引用更新、死锁等)

于 2012-06-04T13:00:02.757 回答
2

锁定一个对象会在您的应用程序中全局锁定它。您甚至可以观察其他类中的锁(如果您锁定了公共对象)。

但是,在您的示例代码中,myList.Add(1)不会等待锁,因为您没有将它包装在一个lock中。

当我们说“锁定一个对象”或“获取一个对象锁定”时,这是一种用词不当,因为语句实际上与阻止访问该对象lock没有任何关系。相反,它通过将该对象用作“密钥”来防止多个线程进入锁定的代码块——并且一次只有一个线程可以拥有密钥。所以当你“锁定”一个对象时,所有线程仍然可以自由使用该对象,但一次只有一个线程可以使用该对象进入一个lock块。

于 2012-06-04T13:07:44.757 回答
1

答案是否定的。一旦一个线程获得了某个对象的锁(在您的情况下myList),没有其他线程可以访问该对象的锁,Thread1 将阻塞所有其他线程,直到 Thread1 释放锁,myList但条件是如果其他线程也在尝试锁。

在您的示例中,如果 Thread1 正在执行SomeMethodA()(具有 的锁myList)并且 Thread2 正在执行SomeMethodB()(它没有请求锁),则不会有任何问题,它们也不会相互阻塞

请考虑以下示例以获得更多说明。

class A
{
    private List<int> myList;

    public void SomeMethodA()
    {
       lock (myList)
       {
           //...
       }
    }

    public void SomeMethodB()
    {
        myList.Add(1);
    }

    public void SomeMethodC()
    {
        lock (myList)
        {
            myList.Add(2);
        }
    }
}

Thread1 正在尝试访问SomeMethodA()

Thread2 正在尝试访问SomeMethodB()

Thread3 正在尝试访问SomeMethodC()

Thread1 和 Thread2 将在不相互阻塞的情况下执行,但 Thread3 将被myList锁定,因为这已被 Thread1 获取。

于 2012-06-04T13:20:19.020 回答
0

如果你不把锁放在里面SomeMethodB,所有线程都可以访问它,即使你有一个线程在SomeMethodA' 锁内执行。为了防止线程运行SomeMethodB,您需要像 sehe 那样实现您的方法。

于 2012-06-04T13:04:38.097 回答