多线程使用过程中,除了线程同步的问题要考虑外,异常处理也是经常要面对的事情。
默认主线程捕获不到异步线程的异常
如下代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 namespace ConsoleApplication29 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 //异步线程的异常处理 8 try 9 {10 Task.Factory.StartNew(() => 11 {12 throw new Exception("异步线和发生异常了!");13 });14 }15 catch (Exception ex)16 {17 //这里是捕获不到的18 Console.WriteLine(ex.ToString());19 }20 21 Console.ReadKey();22 }23 }24 }
常用的异常处理方法
1,在异步线程内部使用try/catch
如下代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 namespace ConsoleApplication29 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 //异步线程的异常处理 8 //1,在异步线程内部使用try/catch 9 Task.Factory.StartNew(() =>10 {11 try12 {13 throw new Exception("异步线和发生异常了!");14 }15 catch (Exception ex)16 {17 Console.WriteLine(ex.ToString());18 }19 });20 21 Console.ReadKey();22 }23 }24 }
运行结果:
2,调用Task的Wait方法
如下代码:
注意:
除了调用Task的Wait方法后,在主线程可以捕获异常外,对于有返回值的Task,只要接收了它的返回值就不再需要调用Wait方法了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 namespace ConsoleApplication29 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 //异步线程的异常处理 8 //2,调用Task的Wait方法 9 try10 {11 var task = Task.Factory.StartNew(() =>12 {13 throw new Exception("异步线和发生异常了!");14 });15 task.Wait();16 }17 catch (Exception ex)18 {19 Console.WriteLine(ex.ToString());20 }21 22 Console.ReadKey();23 }24 }25 }
运行结果:
3,在Task的ContinueWith方法中读取Task的Exception属性
如下代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 namespace ConsoleApplication29 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 //异步线程的异常处理 8 //3,在Task的ContinueWith方法中读取Task的Exception属性 9 Task.Factory.StartNew(() =>10 {11 throw new Exception("异步线和发生异常了!");12 }).ContinueWith(t => 13 {14 if (t.IsFaulted)15 {16 Console.WriteLine(t.Exception.InnerException);17 }18 }, TaskContinuationOptions.OnlyOnFaulted);19 20 Console.ReadKey();21 }22 }23 }
运行结果:
4,全局设置TaskScheduler.UnobservedTaskException
如果异步线程里的异常没有被处理,也没有调用Task.Wait方法将异常传给主线程处理,最严重的后果可能会导致整个应用程序奔溃。详细原因参考:
所以,为了保证应用程序不会因为异步线程的异常未被处理导致挂掉,推荐的做法是,全局设置TaskScheduler.UnobservedTaskException。
如果是web程序,可以在Global的Application_Start事件中进行设置,如下代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 protected override void Application_Start(object sender, EventArgs e)2 {3 System.Threading.Tasks.TaskScheduler.UnobservedTaskException += (s, v) =>4 {5 v.SetObserved();6 };7 }