8.1 线程与线程池
线程基础
什么是线程?
线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。在C#中,System.Threading命名空间提供了对线程操作的支持。
线程的生命周期
- 创建:通过
Thread类实例化一个新线程 - 就绪:调用
Start()方法后线程进入就绪状态 - 运行:被线程调度器选中后执行线程代码
- 阻塞:遇到同步操作或调用
Sleep()时 - 终止:线程执行完成或被中止
线程池(ThreadPool)
为什么需要线程池?
- 减少线程创建和销毁的开销
- 限制并发线程数量,防止资源耗尽
- 自动管理线程生命周期
使用线程池
ThreadPool.QueueUserWorkItem(state =>
{
// 执行后台任务
Console.WriteLine("线程池线程执行中...");
});
线程同步
常见同步机制
lock语句(Monitor类)
private static readonly object _lockObj = new object(); lock(_lockObj) { // 临界区代码 }Mutex(互斥体)
using var mutex = new Mutex(false, "Global\\MyMutex"); mutex.WaitOne(); try { // 受保护的代码 } finally { mutex.ReleaseMutex(); }Semaphore(信号量)
SemaphoreSlim semaphore = new SemaphoreSlim(3); // 允许3个并发 await semaphore.WaitAsync(); try { // 受保护的代码 } finally { semaphore.Release(); }
线程安全实践
最佳实践
- 尽量减少共享数据
- 使用不可变对象
- 优先使用线程安全集合(如
ConcurrentDictionary) - 避免死锁(按固定顺序获取锁)
常见问题
- 竞态条件:多个线程同时访问共享数据
- 死锁:多个线程互相等待对方释放资源
- 线程饥饿:某些线程长期得不到执行机会
性能考量
线程 vs 线程池
| 特性 | 线程 | 线程池 |
|---|---|---|
| 创建开销 | 高 | 低 |
| 数量控制 | 手动管理 | 自动管理 |
| 适合场景 | 长期运行任务 | 短时间任务 |
线程数量建议
- CPU密集型任务:线程数 ≈ CPU核心数
- I/O密集型任务:可以适当增加线程数
注意:在.NET Core/.NET 5+中,
ThreadPool已针对现代硬件进行了优化,通常不需要手动设置线程池大小。
