lock关键字通过互斥锁确保代码块线程安全,使用私有readonly对象作为锁目标,防止多线程并发访问临界区;建议避免锁定this、字符串等,缩小锁定范围,并结合并发集合、Interlocked等机制提升性能与安全性。

在C#中,lock关键字用于确保一段代码在同一时间只能被一个线程执行,从而实现线程安全。它本质上是对指定对象应用一个互斥锁(Monitor),防止多个线程同时进入临界区。
lock关键字的基本用法
使用lock时,需要传入一个引用类型对象作为锁的目标。通常建议使用私有的、readonly的对象实例,避免外部干扰。
示例:private readonly object _lockObject = new object();
public void DoSomething()
{
lock (_lockObject)
{
// 这段代码同一时间只能被一个线程执行
Console.WriteLine("正在执行临界区代码");
}
}
当一个线程进入lock块时,它会尝试获取锁。如果另一个线程已经持有该锁,当前线程将被阻塞,直到锁被释放。
如何实现线程安全
线程安全意味着多个线程访问共享资源时不会导致数据不一致或异常行为。除了lock,还有多种方式可以实现线程安全:
- 使用lock保护共享状态:对读写共享变量的代码加锁,是最常见的方式。
- 使用并发集合类:如ConcurrentDictionary、ConcurrentQueue等,这些类内部已处理线程同步问题。
- 使用Interlocked类:适用于简单的原子操作,比如递增、交换等。
- 使用ReaderWriterLockSlim:适合读多写少场景,允许多个读线程同时访问,写线程独占访问。
- 避免共享状态:通过设计让每个线程拥有独立的数据,从根本上避免竞争。
注意事项和最佳实践
正确使用lock很重要,否则可能引发死锁或性能问题。
- 不要锁定this、typeof(YourClass)或字符串常量,因为它们可能被外部访问或存在相同引用。
- 尽量缩小lock的作用范围,只锁定必要的代码段,提高并发性能。
- 避免在lock块中调用外部方法,以防死锁(外部方法可能反过来尝试获取同一个锁)。
- lock的对象必须是引用类型,值类型会导致装箱,每次都是新对象,无法正确同步。
基本上就这些。lock是C#中最简单直接的线程同步手段,配合良好的设计能有效保证线程安全。虽然还有更高级的机制如async/await、信号量等,但在多数场景下,合理使用lock已经足够解决问题。









