1.线程中的异常处理
一般线程里面不允许出现异常,需要自己处理好,最好在线程里加个try catch,
#region 异常处理 //线程里面的异常是被吞掉了,因为已经脱离了try 的范围了, WaitAll 抓到多线程里面全部的异常 //线程里面不允许出现异常,自己处理好,最好在线程里加个try catch for (int i = 0; i < 20; i++) { string name = string.Format($"btnThreadCore_Click_{i}"); Action<object> act = t => { //try //{ Thread.Sleep(2000); if (t.ToString().Equals("btnThreadCore_Click_11")) { throw new Exception(string.Format($"{t}执行失败")); } if (t.ToString().Equals("btnThreadCore_Click_12")) { throw new Exception(string.Format($"{t}执行失败")); } Console.WriteLine("{0}执行成功", t); //} //catch (Exception ex) //{ // Console.WriteLine(ex.Message); //} }; taskList.Add(taskFactory.StartNew(act, name)); } Task.WaitAll(taskList.ToArray()); }
除此之外,可以在主线程中加个Try Catch ,使用AggregaException 进行捕获异常,注意try中要使用Task.WaitAll ,保证线程都运行完成,才能捕获得到
try
{
//多线程操作
Task.WaitAll(taskList.ToArray());
}
catch (AggregateException aex) { foreach (var item in aex.InnerExceptions) { Console.WriteLine(item.Message+"jj"); } }
2.线程取消:CancellationTokenSource
//多个线程并发,某个失败后,希望通知别的线程,都停下来 //task是外部无法中止的 //线程自己停止自己--公共的访问变量--修改它--线程不断的检测它 //CancellationTokenSource去标志任务是否取消, Cancal 取消 IsCancellationRequested 是否已经取消了 //Token 启动Task的时候传入,那么如果Cancel了,这个任务会放弃启动,抛出一个异常 CancellationTokenSource cts = new CancellationTokenSource();//bool值 for (int i = 0; i < 40; i++) { string name = string.Format("btnThreadCore_Click{0}", i); Action<object> act = t => { try { Thread.Sleep(2000); if (t.ToString().Equals("btnThreadCore_Click11")) { throw new Exception(string.Format("{0}执行失败", t)); } if (t.ToString().Equals("btnThreadCore_Click12")) { throw new Exception(string.Format("{0}执行失败", t)); } if (cts.IsCancellationRequested) { Console.WriteLine("{0}放弃执行", t); return; } else { Console.WriteLine("{0}执行成功", t); } } catch (Exception ex) { cts.Cancel(); Console.WriteLine(ex.Message + "oo"); } }; taskList.Add(taskFactory.StartNew(act, name, cts.Token)); } Task.WaitAll(taskList.ToArray());
3.多线程临时变量需注意
//全程就只有一个i //全程有5个k for (int i = 0; i < 5; i++) { int k = i; Task.Run(() => { Thread.Sleep(100); Console.WriteLine(k); }); }
4.线程安全:使用lock
//lock 解决,因为只有一个线程可以进去,没有并发,所以解决了问题,但是牺牲了性能 //安全队列 ConcurrentQueue 一个线程去完成操作 // for (int i = 0;i< 10000; i++) { int newI = i; taskList.Add(taskFactory.StartNew(() => { lock (btnThreadCore_Click_Lock)//lock后的方法块,任意时刻只有一个线程可以进入,只能锁引用类型,不要用string,因为享元 { TotalCount += 1; IntList.Add(newI); } Monitor.Enter(btnThreadCore_Click_Lock); //和lock一样的效果 Monitor.Exit(btnThreadCore_Click_Lock); })); } Task.WaitAll(taskList.ToArray()); Console.WriteLine(TotalCount); Console.WriteLine(IntList.Count());
5.Asyc await会成对使用,使用之后,方法名前也要加个Task;当遇到await后,后返回到主线程运行,当task的逻辑执行完之后,后执行方法后的逻辑
private static async Task<long> SumAsync() { Console.WriteLine("SumAsync 1111 start"); long result = 0; await Task.Run(() => { for (int k = 0; k < 10; k++) { Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); Thread.Sleep(1000); } for(long i = 0; i < 999999; i++) { result += i; } }); Console.WriteLine($"SumFactory 111 end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}"); return result; }
Task<long> t = SumAsync(); long lResult = t.Result;//这种也会等子线程,获取返回值,等待的部分相当于t.wait() t.Wait();
标签:btnThreadCore,Task,Console,string,ThreadCore,学习,线程,WriteLine From: https://www.cnblogs.com/guoxu486/p/18362065