1、**lock 语句(Monitor 类)**:
-
是最常用的同步机制,用于确保同一时间只有一个线程可以访问某个代码块(临界区)。
-
使用简单,只需指定一个对象作为锁。
csprivate readonly object _lock = new object(); public void CriticalSection() { lock (_lock) { // 临界区代码 } }
2、**Mutex(互斥锁)**:
- 类似于lock,但可以跨进程使用(系统级别的互斥)。
- 使用WaitOne()获取锁,ReleaseMutex()释放锁。
cs
private static Mutex mutex = new Mutex();
public void CriticalSection()
{
mutex.WaitOne();
try
{
// 临界区代码
}
finally
{
mutex.ReleaseMutex();
}
}
3、**Semaphore(信号量)**:
- 控制同时访问某个资源的线程数量,可以指定多个线程同时访问。
- Semaphore 和 SemaphoreSlim(轻量级,适用于进程内同步)。
cs
private static SemaphoreSlim semaphore = new SemaphoreSlim(3); // 允许3个线程同时访问
public async Task CriticalSectionAsync()
{
await semaphore.WaitAsync();
try
{
// 临界区代码
}
finally
{
semaphore.Release();
}
4、ManualResetEvent 和 AutoResetEvent:
- 用于线程间的信号通知。ManualResetEvent需要手动重置,AutoResetEvent在发出信号后自动重置。
cs
private static AutoResetEvent resetEvent = new AutoResetEvent(false);
public void Thread1()
{
// 等待信号
resetEvent.WaitOne();
// 执行操作
}
public void Thread2()
{
// 发送信号
resetEvent.Set();
}
5、ReaderWriterLockSlim:
- 允许多个线程同时读取,但只允许一个线程写入。适用于读多写少的场景。
cs
private static ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
public void ReadOperation()
{
rwLock.EnterReadLock();
try
{
// 读取操作
}
finally
{
rwLock.ExitReadLock();
}
}
public void WriteOperation()
{
rwLock.EnterWriteLock();
try
{
// 写入操作
}
finally
{
rwLock.ExitWriteLock();
}
}
6、**SpinLock(自旋锁)**:
- 一种忙等待的锁,适用于等待时间非常短的场景,避免线程切换的开销。
- 注意:长时间等待会浪费CPU资源。
cs
private static SpinLock spinLock = new SpinLock();
public void CriticalSection()
{
bool lockTaken = false;
try
{
spinLock.Enter(ref lockTaken);
// 临界区代码
}
finally
{
if (lockTaken)
spinLock.Exit();
}
}
7、Interlocked 类:
-
提供原子操作,用于简单的整数和引用类型的操作(如递增、递减、交换等)。
csprivate int counter = 0; public void IncrementCounter() { Interlocked.Increment(ref counter); }
8、系统自带集合方式
8.1**并发集合(System.Collections.Concurrent 命名空间)**:
- 如ConcurrentQueue,ConcurrentDictionary,ConcurrentBag等,它们内部实现了线程安全,可以在多线程环境中直接使用而无需额外的锁。
8.2**Immutable Collections(不可变集合)**:
- 不可变集合是线程安全的,因为任何修改都会创建一个新的集合,适用于读多写少且数据变化不频繁的场景。
9、异步编程Task 和 async/await
- 虽然主要用于异步编程,但通过Task.ContinueWith、Task.WaitAll等也可以实现同步。
- 结合CancellationToken可以控制任务取消。
10、总结:
根据具体场景选择适当的同步机制:
- 对于简单的临界区,使用lock即可。
- 需要控制并发线程数量时,使用Semaphore/SemaphoreSlim。
- 进程间同步使用Mutex。
- 读写分离使用ReaderWriterLockSlim。
- 等待事件通知使用AutoResetEvent/ManualResetEvent。
- 原子操作使用Interlocked类。
- 高性能场景且等待时间短时考虑SpinLock。
- 异步环境可以使用SemaphoreSlim的WaitAsync方法。