17、线程池
线程池
知识点概述
线程池是.NET Framework提供的重要特性,用于管理和重用线程资源。线程池可以显著提高应用程序性能,避免频繁创建和销毁线程的开销。
主要特点:
- 线程重用: 避免重复创建销毁线程的开销
- 自动管理: 系统自动调整线程池大小
- 工作项队列: 使用队列管理待执行的任务
- 后台线程: 线程池中的线程都是后台线程
- 线程数限制: 有最大和最小线程数限制
代码案例
案例1:ThreadPool基本使用
using System;
using System.Threading;
class ThreadPoolBasicDemo
{
static void Main()
{
Console.WriteLine("ThreadPool 基本使用演示:");
// 获取线程池信息
int workerThreads, completionPortThreads;
ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);
Console.WriteLine($"最大工作线程数: {workerThreads}");
Console.WriteLine($"最大I/O完成线程数: {completionPortThreads}");
ThreadPool.GetMinThreads(out workerThreads, out completionPortThreads);
Console.WriteLine($"最小工作线程数: {workerThreads}");
Console.WriteLine($"最小I/O完成线程数: {completionPortThreads}");
Console.WriteLine("\n向线程池提交工作项:");
// 向线程池提交工作
for (int i = 1; i <= 5; i++)
{
int taskId = i;
ThreadPool.QueueUserWorkItem(DoWork, taskId);
}
// 等待所有工作完成
Thread.Sleep(3000);
Console.WriteLine("所有任务完成");
}
static void DoWork(object state)
{
int taskId = (int)state;
int threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine($"任务 {taskId} 在线程 {threadId} 上开始执行");
// 模拟工作
Thread.Sleep(1000);
Console.WriteLine($"任务 {taskId} 在线程 {threadId} 上完成");
}
}
案例2:使用ManualResetEvent等待线程池任务完成
using System;
using System.Threading;
class ThreadPoolWithSynchronization
{
private static ManualResetEvent[] _resetEvents;
private static int _taskCount = 4;
static void Main()
{
_resetEvents = new ManualResetEvent[_taskCount];
Console.WriteLine($"启动 {_taskCount} 个线程池任务:");
// 启动多个任务
for (int i = 0; i < _taskCount; i++)
{
_resetEvents[i] = new ManualResetEvent(false);
int taskIndex = i;
ThreadPool.QueueUserWorkItem(ProcessTask, taskIndex);
}
Console.WriteLine("等待所有任务完成...");
// 等待所有任务完成
WaitHandle.WaitAll(_resetEvents);
Console.WriteLine("所有任务已完成!");
// 清理资源
foreach (var resetEvent in _resetEvents)
{
resetEvent.Dispose();
}
}
static void ProcessTask(object state)
{
int taskIndex = (int)state;
int threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine($"任务 {taskIndex} 开始 (线程ID: {threadId})");
// 模拟不同长度的工作
Random rand = new Random(taskIndex);
int workTime = rand.Next(1000, 3000);
Thread.Sleep(workTime);
Console.WriteLine($"任务 {taskIndex} 完成 (耗时: {workTime}ms, 线程ID: {threadId})");
// 标记任务完成
_resetEvents[taskIndex].Set();
}
}
案例3:线程池性能对比
using System;
using System.Threading;
using System.Diagnostics;
using System.Collections.Generic;
class ThreadPoolPerformanceComparison
{
static void Main()
{
int taskCount = 20;
Console.WriteLine($"性能对比测试 - 执行 {taskCount} 个任务");
Console.WriteLine("====================================");
// 测试普通线程创建
TestRegularThreads(taskCount);
// 等待一下再测试线程池
Thread.Sleep(1000);
// 测试线程池
TestThreadPool(taskCount);
}
static void TestRegularThreads(int taskCount)
{
Console.WriteLine("\n1. 使用普通Thread:");
Stopwatch sw = Stopwatch.StartNew();
List<Thread> threads = new List<Thread>();
for (int i = 0; i < taskCount; i++)
{
int taskId = i;
Thread thread = new Thread(() => SimulateWork(taskId, "Thread"));
threads.Add(thread);
thread.Start();
}
// 等待所有线程完成
foreach (Thread thread in threads)
{
thread.Join();
}
sw.Stop();
Console.WriteLine($"普通线程总耗时: {sw.ElapsedMilliseconds}ms");
}
static void TestThreadPool(int taskCount)
{
Console.WriteLine("\n2. 使用ThreadPool:");
Stopwatch sw = Stopwatch.StartNew();
ManualResetEvent[] resetEvents = new ManualResetEvent[taskCount];
for (int i = 0; i < taskCount; i++)
{
resetEvents[i] = new ManualResetEvent(false);
int taskId = i;
ThreadPool.QueueUserWorkItem(_ =>
{
SimulateWork(taskId, "ThreadPool");
resetEvents[taskId].Set();
});
}
// 等待所有任务完成
WaitHandle.WaitAll(resetEvents);
sw.Stop();
Console.WriteLine($"线程池总耗时: {sw.ElapsedMilliseconds}ms");
// 清理资源
foreach (var resetEvent in resetEvents)
{
resetEvent.Dispose();
}
}
static void SimulateWork(int taskId, string threadType)
{
int threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine($"{threadType} 任务 {taskId} 开始 (线程ID: {threadId})");
// 模拟CPU密集型工作
long sum = 0;
for (int i = 0; i < 1000000; i++)
{
sum += i;
}
Console.WriteLine($"{threadType} 任务 {taskId} 完成 (线程ID: {threadId})");
}
}
案例4:调整线程池设置
using System;
using System.Threading;
using System.Diagnostics;
class ThreadPoolConfiguration
{
static void Main()
{
Console.WriteLine("线程池配置演示:");
// 显示当前线程池设置
DisplayThreadPoolInfo();
Console.WriteLine("\n调整线程池设置:");
// 设置最小线程数
ThreadPool.SetMinThreads(4, 4);
// 设置最大线程数(注意:通常不建议减小最大线程数)
int maxWorkerThreads, maxCompletionPortThreads;
ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxCompletionPortThreads);
ThreadPool.SetMaxThreads(Math.Min(maxWorkerThreads, 8), maxCompletionPortThreads);
DisplayThreadPoolInfo();
Console.WriteLine("\n测试线程池行为:");
TestThreadPoolBehavior();
}
static void DisplayThreadPoolInfo()
{
int workerThreads, completionPortThreads;
int availableWorkerThreads, availableCompletionPortThreads;
ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);
ThreadPool.GetMinThreads(out availableWorkerThreads, out availableCompletionPortThreads);
Console.WriteLine($"最大线程数 - 工作线程: {workerThreads}, I/O线程: {completionPortThreads}");
Console.WriteLine($"最小线程数 - 工作线程: {availableWorkerThreads}, I/O线程: {availableCompletionPortThreads}");
ThreadPool.GetAvailableThreads(out availableWorkerThreads, out availableCompletionPortThreads);
Console.WriteLine($"可用线程数 - 工作线程: {availableWorkerThreads}, I/O线程: {availableCompletionPortThreads}");
}
static void TestThreadPoolBehavior()
{
int taskCount = 10;
CountdownEvent countdown = new CountdownEvent(taskCount);
Console.WriteLine($"提交 {taskCount} 个任务到线程池:");
for (int i = 0; i < taskCount; i++)
{
int taskId = i;
ThreadPool.QueueUserWorkItem(_ =>
{
int threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine($"任务 {taskId} 开始执行 (线程ID: {threadId}) - {DateTime.Now:HH:mm:ss.fff}");
Thread.Sleep(2000); // 模拟工作
Console.WriteLine($"任务 {taskId} 完成 (线程ID: {threadId}) - {DateTime.Now:HH:mm:ss.fff}");
countdown.Signal();
});
}
countdown.Wait();
Console.WriteLine("所有任务完成");
countdown.Dispose();
}
}
案例5:线程池中的异常处理
using System;
using System.Threading;
class ThreadPoolExceptionHandling
{
static void Main()
{
Console.WriteLine("线程池异常处理演示:");
// 设置未处理异常事件处理器
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
// 提交会抛出异常的任务
for (int i = 0; i < 3; i++)
{
int taskId = i;
ThreadPool.QueueUserWorkItem(FaultyTask, taskId);
}
// 提交正常任务
for (int i = 3; i < 6; i++)
{
int taskId = i;
ThreadPool.QueueUserWorkItem(SafeTask, taskId);
}
Thread.Sleep(3000);
Console.WriteLine("主线程继续执行");
}
static void FaultyTask(object state)
{
int taskId = (int)state;
try
{
Console.WriteLine($"有问题的任务 {taskId} 开始");
if (taskId % 2 == 0)
{
throw new InvalidOperationException($"任务 {taskId} 故意抛出异常");
}
Thread.Sleep(1000);
Console.WriteLine($"有问题的任务 {taskId} 正常完成");
}
catch (Exception ex)
{
Console.WriteLine($"任务 {taskId} 异常被捕获: {ex.Message}");
}
}
static void SafeTask(object state)
{
int taskId = (int)state;
try
{
Console.WriteLine($"安全任务 {taskId} 开始");
Thread.Sleep(800);
Console.WriteLine($"安全任务 {taskId} 完成");
}
catch (Exception ex)
{
Console.WriteLine($"安全任务 {taskId} 意外异常: {ex.Message}");
}
}
static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine($"未处理的异常: {e.ExceptionObject}");
}
}
案例6:监控线程池状态
using System;
using System.Threading;
using System.Threading.Tasks;
class ThreadPoolMonitoring
{
private static bool _monitoring = true;
static async Task Main()
{
Console.WriteLine("线程池监控演示:");
// 启动监控任务
Task monitorTask = Task.Run(MonitorThreadPool);
// 模拟工作负载
await SimulateWorkload();
// 停止监控
_monitoring = false;
await monitorTask;
Console.WriteLine("监控结束");
}
static void MonitorThreadPool()
{
Console.WriteLine("开始监控线程池状态...\n");
while (_monitoring)
{
int availableWorkerThreads, availableCompletionPortThreads;
int maxWorkerThreads, maxCompletionPortThreads;
ThreadPool.GetAvailableThreads(out availableWorkerThreads, out availableCompletionPortThreads);
ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxCompletionPortThreads);
int busyWorkerThreads = maxWorkerThreads - availableWorkerThreads;
int busyCompletionPortThreads = maxCompletionPortThreads - availableCompletionPortThreads;
Console.Clear();
Console.WriteLine("线程池状态监控");
Console.WriteLine("================");
Console.WriteLine($"工作线程: {busyWorkerThreads}/{maxWorkerThreads} 正在使用");
Console.WriteLine($"I/O线程: {busyCompletionPortThreads}/{maxCompletionPortThreads} 正在使用");
Console.WriteLine($"可用工作线程: {availableWorkerThreads}");
Console.WriteLine($"可用I/O线程: {availableCompletionPortThreads}");
Console.WriteLine($"监控时间: {DateTime.Now:HH:mm:ss}");
Thread.Sleep(500);
}
}
static async Task SimulateWorkload()
{
Console.WriteLine("开始模拟工作负载...");
// 阶段1:轻负载
for (int i = 0; i < 3; i++)
{
ThreadPool.QueueUserWorkItem(_ => Thread.Sleep(2000));
}
await Task.Delay(3000);
// 阶段2:中等负载
for (int i = 0; i < 6; i++)
{
ThreadPool.QueueUserWorkItem(_ => Thread.Sleep(3000));
}
await Task.Delay(4000);
// 阶段3:高负载
for (int i = 0; i < 12; i++)
{
ThreadPool.QueueUserWorkItem(_ => Thread.Sleep(2000));
}
await Task.Delay(5000);
}
}
知识点总结
- 资源重用: 线程池通过重用线程减少创建/销毁开销,提高性能
- 自动管理: 系统根据负载自动调整线程池大小
- 工作项队列: 使用FIFO队列管理待执行的任务
- 配置选项: 可以调整最大/最小线程数,但要谨慎设置
- 异常处理: 线程池中的异常需要在任务内部处理
- 性能监控: 监控线程池状态有助于优化应用程序性能
- 使用场景: 适合短时间运行的任务,长时间运行的任务应使用专用线程

浙公网安备 33010602011771号