我看到,对于使用非线程安全的对象,我们用这样的锁包装代码:

private static readonly Object obj = new Object();

lock (obj)
{
    // thread unsafe code
}

那么,当多个线程访问相同的代码时会发生什么(让我们假设它运行在一个ASP。NET web应用程序)。他们排队了吗?如果是的话,他们要等多久?

使用锁对性能有什么影响?


当前回答

锁将阻止其他线程执行锁块中包含的代码。线程将不得不等待,直到锁块内的线程完成并释放锁。这确实会对多线程环境中的性能产生负面影响。如果您确实需要这样做,您应该确保锁块中的代码可以非常快速地处理。你应该尽量避免昂贵的活动,如访问数据库等。

其他回答

lock语句被转换为对Monitor的Enter和Exit方法的调用。

lock语句将无限期地等待锁定对象被释放。

锁语句中的部分只能由一个线程执行,因此所有其他线程将无限期地等待持有锁的线程完成。这可能导致所谓的死锁。

根据微软的MSDN,这个锁相当于:

object __lockObj = x;
bool __lockWasTaken = false;
try
{
    System.Threading.Monitor.Enter(__lockObj, ref __lockWasTaken);
    // Your code...
}
finally
{
    if (__lockWasTaken) System.Threading.Monitor.Exit(__lockObj);
}

如果需要在运行时创建锁,可以使用开源的DynaLock。您可以在运行时创建新锁,并使用上下文概念指定锁的边界。

DynaLock是开源的,源代码可以在GitHub上获得

锁将阻止其他线程执行锁块中包含的代码。线程将不得不等待,直到锁块内的线程完成并释放锁。这确实会对多线程环境中的性能产生负面影响。如果您确实需要这样做,您应该确保锁块中的代码可以非常快速地处理。你应该尽量避免昂贵的活动,如访问数据库等。

这比你想的要简单

微软表示: lock关键字确保当另一个线程处于临界区时,一个线程不会进入临界区。如果另一个线程试图输入一个锁定的代码,它将等待,阻塞,直到对象被释放。

lock关键字在块的开始调用Enter,在块的结束调用Exit。lock关键字实际上在后端处理Monitor类。

例如:

private static readonly Object obj = new Object();

lock (obj)
{
    // critical section
}

在上面的代码中,首先线程进入临界区,然后它将锁定obj。当另一个线程试图进入时,它也会尝试锁定obj,它已经被第一个线程锁定了。第二个线程将不得不等待第一个线程释放obj。当第一个线程离开时,另一个线程将锁定obj并进入临界区。