区别
- 资源访问数量限制
- 信号量:可控制同时访问某一资源或代码段的线程数量,允许多个线程同时进入临界区。例如Semaphore可设置初始信号量数量,SemaphoreSlim更是轻量级,适合高频率信号量操作场景。
- 互斥锁:同一时间只允许一个线程进入临界区,用于保护共享资源不被多个线程同时访问。
- 线程所有权
- 信号量:不具有线程所有权概念,任何线程获取信号量后,其他线程都可尝试获取。
- 互斥锁:获取锁的线程拥有该锁,只有拥有锁的线程才能释放它,避免其他线程意外释放。
- 跨进程使用
- 信号量:可用于进程间同步,能在不同进程中共享资源访问控制。
- 互斥锁:主要用于同一进程内线程间同步,虽然也能跨进程,但使用场景相对较少。
应用场景举例
- 优先选择信号量
- 场景:如数据库连接池场景,假设连接池有10个连接,同时允许10个线程获取连接进行数据库操作。
- 代码示例:
using System;
using System.Threading;
class Program
{
private static SemaphoreSlim _semaphore = new SemaphoreSlim(10, 10);
static void Main()
{
for (int i = 0; i < 20; i++)
{
new Thread(AccessDatabase).Start();
}
Console.ReadKey();
}
static void AccessDatabase()
{
_semaphore.Wait();
try
{
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} 获取到连接,开始操作数据库");
Thread.Sleep(1000);
Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId} 操作数据库完成,释放连接");
}
finally
{
_semaphore.Release();
}
}
}
- 优先选择互斥锁
- 场景:例如单例模式下,确保全局只有一个实例被创建,在创建实例过程中使用互斥锁防止多个线程同时创建实例。
- 代码示例:
using System;
using System.Threading;
class Singleton
{
private static Singleton _instance;
private static Mutex _mutex = new Mutex();
private Singleton() { }
public static Singleton GetInstance()
{
_mutex.WaitOne();
try
{
if (_instance == null)
{
_instance = new Singleton();
}
return _instance;
}
finally
{
_mutex.ReleaseMutex();
}
}
}