18、线程中的异常处理
线程中的异常处理
知识点概述
线程中的异常处理是多线程编程的重要方面,不正确的异常处理可能导致应用程序崩溃或数据损坏。在.NET中,线程异常处理有以下特点:
- 未处理异常: 线程中未处理的异常会导致应用程序终止
- 异常传播: 线程异常不会自动传播到调用线程
- Task异常: Task提供了更好的异常处理机制
- 聚合异常: 多个任务的异常会被包装在AggregateException中
- 全局异常处理: 可以设置全局异常处理器
代码案例
案例1:Thread中的异常处理
using System;
using System.Threading;
class ThreadExceptionHandling
{
static void Main()
{
Console.WriteLine("Thread异常处理演示:");
// 设置全局未处理异常事件
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
// 创建会抛出异常的线程
Thread faultyThread = new Thread(FaultyWorker);
faultyThread.IsBackground = false; // 设置为前台线程
faultyThread.Start();
// 创建正常工作的线程
Thread normalThread = new Thread(NormalWorker);
normalThread.Start();
// 等待线程完成
try
{
normalThread.Join();
faultyThread.Join();
}
catch (Exception ex)
{
Console.WriteLine($"主线程捕获异常: {ex.Message}");
}
Console.WriteLine("主线程结束");
}
static void FaultyWorker()
{
try
{
Console.WriteLine("有问题的线程开始工作");
Thread.Sleep(1000);
// 故意抛出异常
throw new InvalidOperationException("线程中发生了错误!");
}
catch (Exception ex)
{
Console.WriteLine($"线程内部捕获异常: {ex.Message}");
// 如果不在这里处理,异常会导致应用程序终止
}
}
static void NormalWorker()
{
try
{
Console.WriteLine("正常线程开始工作");
for (int i = 0; i < 3; i++)
{
Console.WriteLine($"正常工作步骤 {i + 1}");
Thread.Sleep(500);
}
Console.WriteLine("正常线程完成工作");
}
catch (Exception ex)
{
Console.WriteLine($"正常线程异常: {ex.Message}");
}
}
static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine($"全局未处理异常: {e.ExceptionObject}");
Console.WriteLine($"应用程序即将终止: {e.IsTerminating}");
}
}
案例2:Task中的异常处理
using System;
using System.Threading.Tasks;
class TaskExceptionHandling
{
static async Task Main()
{
Console.WriteLine("Task异常处理演示:");
// 方式1:使用try-catch处理单个Task异常
await HandleSingleTaskException();
Console.WriteLine("\n" + new string('=', 50) + "\n");
// 方式2:处理多个Task的异常
await HandleMultipleTaskExceptions();
Console.WriteLine("\n" + new string('=', 50) + "\n");
// 方式3:使用ContinueWith处理异常
await HandleExceptionWithContinueWith();
}
static async Task HandleSingleTaskException()
{
Console.WriteLine("1. 单个Task异常处理:");
try
{
await Task.Run(() =>
{
Console.WriteLine("Task开始执行");
Thread.Sleep(1000);
throw new ArgumentException("Task中发生了参数错误!");
});
}
catch (ArgumentException ex)
{
Console.WriteLine($"捕获到ArgumentException: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"捕获到其他异常: {ex.Message}");
}
}
static async Task HandleMultipleTaskExceptions()
{
Console.WriteLine("2. 多个Task异常处理:");
Task task1 = Task.Run(() =>
{
Thread.Sleep(500);
throw new InvalidOperationException("任务1异常");
});
Task task2 = Task.Run(() =>
{
Thread.Sleep(800);
throw new ArgumentNullException("任务2异常");
});
Task task3 = Task.Run(() =>
{
Thread.Sleep(300);
Console.WriteLine("任务3正常完成");
});
try
{
await Task.WhenAll(task1, task2, task3);
}
catch (Exception ex)
{
Console.WriteLine($"第一个异常: {ex.Message}");
// 检查所有任务的异常
CheckAllTaskExceptions(task1, task2, task3);
}
}
static void CheckAllTaskExceptions(params Task[] tasks)
{
Console.WriteLine("检查所有任务状态:");
foreach (var task in tasks)
{
if (task.IsFaulted && task.Exception != null)
{
foreach (var innerEx in task.Exception.InnerExceptions)
{
Console.WriteLine($" - 任务异常: {innerEx.GetType().Name}: {innerEx.Message}");
}
}
else if (task.IsCompletedSuccessfully)
{
Console.WriteLine(" - 任务正常完成");
}
}
}
static async Task HandleExceptionWithContinueWith()
{
Console.WriteLine("3. 使用ContinueWith处理异常:");
Task<int> faultyTask = Task.Run(() =>
{
Thread.Sleep(1000);
throw new DivideByZeroException("除零错误!");
return 42; // 不会执行到这里
});
Task continuationTask = faultyTask.ContinueWith(task =>
{
if (task.IsFaulted)
{
Console.WriteLine($"任务失败: {task.Exception?.GetBaseException().Message}");
return -1;
}
else if (task.IsCompletedSuccessfully)
{
Console.WriteLine($"任务成功,结果: {task.Result}");
return task.Result;
}
else
{
Console.WriteLine("任务被取消");
return 0;
}
});
await continuationTask;
}
}
案例3:聚合异常处理
using System;
using System.Threading.Tasks;
using System.Linq;
class AggregateExceptionHandling
{
static async Task Main()
{
Console.WriteLine("聚合异常处理演示:");
// 创建多个会抛出不同异常的任务
Task[] tasks = new Task[]
{
CreateTaskWithException<ArgumentException>("参数错误", 500),
CreateTaskWithException<InvalidOperationException>("操作无效", 800),
CreateTaskWithException<NotSupportedException>("不支持的操作", 300),
CreateNormalTask("正常任务", 1000),
CreateTaskWithException<DivideByZeroException>("除零错误", 600)
};
try
{
await Task.WhenAll(tasks);
Console.WriteLine("所有任务正常完成");
}
catch (Exception ex)
{
Console.WriteLine($"捕获的第一个异常: {ex.GetType().Name}: {ex.Message}");
// 处理聚合异常
await HandleAggregateExceptions(tasks);
}
}
static Task CreateTaskWithException<T>(string message, int delay) where T : Exception, new()
{
return Task.Run(async () =>
{
await Task.Delay(delay);
Console.WriteLine($"任务抛出 {typeof(T).Name}");
// 使用反射创建异常实例
var exception = (T)Activator.CreateInstance(typeof(T), message);
throw exception;
});
}
static Task CreateNormalTask(string name, int delay)
{
return Task.Run(async () =>
{
await Task.Delay(delay);
Console.WriteLine($"{name} 正常完成");
});
}
static async Task HandleAggregateExceptions(Task[] tasks)
{
Console.WriteLine("\n详细异常分析:");
// 等待所有任务完成(包括失败的)
await Task.WhenAll(tasks.Select(async task =>
{
try
{
await task;
}
catch
{
// 忽略异常,我们只是想等待所有任务完成
}
}));
// 分析各种异常类型
var faultedTasks = tasks.Where(t => t.IsFaulted).ToArray();
if (faultedTasks.Any())
{
Console.WriteLine($"失败任务数量: {faultedTasks.Length}");
// 按异常类型分组
var exceptionGroups = faultedTasks
.SelectMany(t => t.Exception.InnerExceptions)
.GroupBy(ex => ex.GetType())
.ToArray();
foreach (var group in exceptionGroups)
{
Console.WriteLine($"\n{group.Key.Name} ({group.Count()} 个):");
foreach (var exception in group)
{
Console.WriteLine($" - {exception.Message}");
}
}
}
// 统计任务状态
var completedCount = tasks.Count(t => t.IsCompletedSuccessfully);
var faultedCount = tasks.Count(t => t.IsFaulted);
var canceledCount = tasks.Count(t => t.IsCanceled);
Console.WriteLine($"\n任务执行统计:");
Console.WriteLine($"成功: {completedCount}, 失败: {faultedCount}, 取消: {canceledCount}");
}
}
案例4:异常重试机制
using System;
using System.Threading.Tasks;
class ExceptionRetryMechanism
{
static async Task Main()
{
Console.WriteLine("异常重试机制演示:");
// 测试重试机制
try
{
var result = await ExecuteWithRetry(
() => UnreliableOperation(),
maxRetries: 3,
delay: TimeSpan.FromSeconds(1)
);
Console.WriteLine($"操作成功,结果: {result}");
}
catch (Exception ex)
{
Console.WriteLine($"重试失败,最终异常: {ex.Message}");
}
Console.WriteLine("\n" + new string('=', 50) + "\n");
// 测试带条件的重试
await TestConditionalRetry();
}
static async Task<T> ExecuteWithRetry<T>(
Func<Task<T>> operation,
int maxRetries,
TimeSpan delay)
{
Exception lastException = null;
for (int attempt = 1; attempt <= maxRetries + 1; attempt++)
{
try
{
Console.WriteLine($"尝试执行操作 (第 {attempt} 次)");
return await operation();
}
catch (Exception ex)
{
lastException = ex;
Console.WriteLine($"第 {attempt} 次尝试失败: {ex.Message}");
if (attempt <= maxRetries)
{
Console.WriteLine($"等待 {delay.TotalSeconds} 秒后重试...");
await Task.Delay(delay);
}
}
}
throw new InvalidOperationException(
$"操作在 {maxRetries + 1} 次尝试后仍然失败", lastException);
}
static async Task<string> UnreliableOperation()
{
await Task.Delay(500);
// 模拟不可靠的操作,70%概率失败
if (new Random().NextDouble() < 0.7)
{
throw new InvalidOperationException("模拟的网络错误");
}
return "操作成功完成";
}
static async Task TestConditionalRetry()
{
Console.WriteLine("条件重试演示:");
try
{
await ExecuteWithConditionalRetry();
}
catch (Exception ex)
{
Console.WriteLine($"条件重试最终失败: {ex.Message}");
}
}
static async Task ExecuteWithConditionalRetry()
{
int maxRetries = 3;
int attempt = 0;
while (attempt <= maxRetries)
{
attempt++;
try
{
await SimulateOperationWithDifferentErrors(attempt);
Console.WriteLine("操作成功完成");
return;
}
catch (ArgumentException ex)
{
Console.WriteLine($"参数错误不重试: {ex.Message}");
throw; // 参数错误不应该重试
}
catch (InvalidOperationException ex) when (attempt <= maxRetries)
{
Console.WriteLine($"临时错误,准备重试: {ex.Message}");
await Task.Delay(1000);
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"重试次数已用尽: {ex.Message}");
throw;
}
}
}
static async Task SimulateOperationWithDifferentErrors(int attempt)
{
await Task.Delay(300);
switch (attempt)
{
case 1:
throw new InvalidOperationException("网络超时 - 可重试");
case 2:
throw new InvalidOperationException("服务暂时不可用 - 可重试");
case 3:
throw new ArgumentException("无效的请求参数 - 不应重试");
default:
Console.WriteLine("操作执行成功");
break;
}
}
}
案例5:异常日志和监控
using System;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.IO;
class ExceptionLoggingAndMonitoring
{
private static readonly ConcurrentQueue<ExceptionInfo> _exceptionLog = new ConcurrentQueue<ExceptionInfo>();
static async Task Main()
{
Console.WriteLine("异常日志和监控演示:");
// 启动异常监控
Task monitoringTask = StartExceptionMonitoring();
// 模拟多个任务运行
Task[] workTasks = new Task[]
{
RunTaskWithLogging("任务1", () => throw new ArgumentException("参数错误")),
RunTaskWithLogging("任务2", () => Thread.Sleep(1000)),
RunTaskWithLogging("任务3", () => throw new InvalidOperationException("操作错误")),
RunTaskWithLogging("任务4", () => Thread.Sleep(500)),
RunTaskWithLogging("任务5", () => throw new DivideByZeroException("除零错误"))
};
// 等待所有工作任务完成
await Task.WhenAll(workTasks.Select(async task =>
{
try
{
await task;
}
catch
{
// 异常已经被记录
}
}));
// 等待一下让监控输出完整信息
await Task.Delay(2000);
// 生成异常报告
await GenerateExceptionReport();
Console.WriteLine("演示完成");
}
static async Task<T> RunTaskWithLogging<T>(string taskName, Func<T> operation)
{
try
{
Console.WriteLine($"{taskName} 开始执行");
var result = await Task.Run(operation);
Console.WriteLine($"{taskName} 成功完成");
return result;
}
catch (Exception ex)
{
// 记录异常
LogException(taskName, ex);
Console.WriteLine($"{taskName} 执行失败: {ex.Message}");
throw;
}
}
static void LogException(string context, Exception exception)
{
var exceptionInfo = new ExceptionInfo
{
Context = context,
Exception = exception,
Timestamp = DateTime.Now,
ThreadId = System.Threading.Thread.CurrentThread.ManagedThreadId
};
_exceptionLog.Enqueue(exceptionInfo);
}
static Task StartExceptionMonitoring()
{
return Task.Run(async () =>
{
Console.WriteLine("异常监控已启动...\n");
int lastCount = 0;
while (true)
{
int currentCount = _exceptionLog.Count;
if (currentCount > lastCount)
{
Console.WriteLine($"[监控] 检测到 {currentCount - lastCount} 个新异常");
lastCount = currentCount;
}
await Task.Delay(1000);
// 简单的退出条件
if (currentCount > 0 && DateTime.Now.Second % 10 == 0)
{
break;
}
}
});
}
static async Task GenerateExceptionReport()
{
Console.WriteLine("\n生成异常报告:");
Console.WriteLine("================");
var exceptions = _exceptionLog.ToArray();
if (!exceptions.Any())
{
Console.WriteLine("没有记录到异常");
return;
}
// 按异常类型分组统计
var exceptionStats = exceptions
.GroupBy(e => e.Exception.GetType().Name)
.Select(g => new { Type = g.Key, Count = g.Count() })
.OrderByDescending(s => s.Count);
Console.WriteLine("异常类型统计:");
foreach (var stat in exceptionStats)
{
Console.WriteLine($" {stat.Type}: {stat.Count} 次");
}
Console.WriteLine("\n详细异常列表:");
foreach (var info in exceptions.OrderBy(e => e.Timestamp))
{
Console.WriteLine($"[{info.Timestamp:HH:mm:ss.fff}] {info.Context} - " +
$"{info.Exception.GetType().Name}: {info.Exception.Message} " +
$"(线程ID: {info.ThreadId})");
}
// 保存到文件
await SaveExceptionReportToFile(exceptions);
}
static async Task SaveExceptionReportToFile(ExceptionInfo[] exceptions)
{
string fileName = $"exception_report_{DateTime.Now:yyyyMMdd_HHmmss}.txt";
using (StreamWriter writer = new StreamWriter(fileName))
{
await writer.WriteLineAsync($"异常报告 - 生成时间: {DateTime.Now}");
await writer.WriteLineAsync(new string('=', 50));
foreach (var info in exceptions)
{
await writer.WriteLineAsync($"时间: {info.Timestamp}");
await writer.WriteLineAsync($"上下文: {info.Context}");
await writer.WriteLineAsync($"异常类型: {info.Exception.GetType().FullName}");
await writer.WriteLineAsync($"异常消息: {info.Exception.Message}");
await writer.WriteLineAsync($"线程ID: {info.ThreadId}");
await writer.WriteLineAsync($"堆栈跟踪:\n{info.Exception.StackTrace}");
await writer.WriteLineAsync(new string('-', 30));
}
}
Console.WriteLine($"\n异常报告已保存到: {fileName}");
}
class ExceptionInfo
{
public string Context { get; set; }
public Exception Exception { get; set; }
public DateTime Timestamp { get; set; }
public int ThreadId { get; set; }
}
}
知识点总结
- 异常隔离: 线程中的异常不会自动传播,需要显式处理
- 全局处理: 设置AppDomain.UnhandledException处理未捕获的异常
- Task优势: Task提供了比Thread更好的异常处理机制
- 聚合异常: 多任务场景下使用AggregateException处理多个异常
- 重试机制: 对于临时性错误,可以实现自动重试机制
- 异常分类: 区分可重试和不可重试的异常类型
- 监控日志: 建立完善的异常记录和监控机制有助于问题诊断

浙公网安备 33010602011771号