异步多线程的异常,抓不到,因为是在子线程执行。
#region 多线程的异常处理、线程取消、临时变量、lock { try { List<Task> list = new List<Task>(); TaskFactory taskFactory = new TaskFactory(); //取消线程 CancellationTokenSource cts = new CancellationTokenSource(); for (int i = 0; i < 5; i++) { string name = "task" + i; //无参数,无返回值的一个委托 Action act = new Action(() => { try { if (name == "task4") { throw new Exception("抛出异常信息"); } Thread.Sleep(2000); //检查Task是否被取消了 if (cts.IsCancellationRequested) { Console.WriteLine(name + " 被取消:" + cts.IsCancellationRequested); } else { Console.WriteLine(name + " 执行成功"); } } catch (Exception ex) { cts.Cancel();//取消,所有子线程都会被取消 Console.WriteLine("子线程异常:{0}", ex.Message); } }); Task task = taskFactory.StartNew(act, cts.Token); list.Add(task); //cts.Token是一个标识,用来标记线程是否已经被取消了 //输出结果 //子线程异常:抛出异常信息 //task2 被取消:True //task1 被取消:True //task3 被取消:True //task0 被取消:True } Task.WaitAll(list.ToArray()); } catch (AggregateException ex) { foreach (var item in ex.InnerExceptions) { Console.WriteLine(item.Message); } } } #endregion #region 多线程延迟问题 { Action<int> act = new Action<int>(t => { Thread.Sleep(200); Console.WriteLine(t); }); for (int i = 0; i < 10; i++) { //Task.Run 需要接受 无参数、无返回值 的Action,所以需要包装一下 //会出现错误,输出的全部是 10,因为Task.Run去申请线程后并没有立即执行,当执行的时候for循环已经结束,i已经变成10了 //Task.Run(() => act(i)); //解决方法,每次循环都会创建一个新的变量k,执行的时候引用的是当时的k int k = i; Task.Run(() => act(k)); } } #endregion
线程变量副本ThreadLocal/ThreadStatic
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | static ThreadLocal< string > threadLocal = new ThreadLocal< string >(); static void Main( string [] args) { List<Task> list = new List<Task>(); for ( int i = 0; i < 4; i++) { Task task = Task.Run(() =>{ Thread.Sleep(2000); threadLocal.Value = "线程" + Thread.CurrentThread.ManagedThreadId; PrintLocalData(); }); list.Add(task); } Task.WaitAll(list.ToArray()); } public static void PrintLocalData() { Console.WriteLine( "{0}:{1}" , Thread.CurrentThread.ManagedThreadId, threadLocal.Value); } |
结果:5:线程5
8:线程8
9:线程9
11:线程11
ThreadLocal的源码中很简单,就是使用了ThreadStatic特性:[ThreadStatic]使每个线程都有一个变量副本。
所以,上面的static ThreadLocal<string> threadLocal = new ThreadLocal<string>(); 可以替换为:
[ThreadStatic]
static string localValue;
注:[ThreadStatic]依赖当前线程,当线程池的线程被重用时,可能该字段又表现为“公用”的了。及时清空可以一定程度上解决该问题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】