void 异常捕获(){try{new Thread(Go).Start();// 启动t线程,执行Go方法}catch (Exception e){_testOutputHelper.WriteLine(e.Message);}}void Go() => throw null!;// 抛出空指针异常
解决方案是将异常处理移到Go方法中:自己的异常,自己解决
static void Go(){try{// ...throw null;// 异常会在下面被捕获// ...}catch (Exception ex){// 一般会记录异常,或通知其它线程我们遇到问题了// ...}}
AppDomain.CurrentDomain.UnhandledException 会对所有未处理的异常触发,因此它可以用于集中记录线程发生的异常,但是它不能阻止程序退出 。
void UnhandledException(){AppDomain.CurrentDomain.UnhandledException += HandleUnHandledException;new Thread(Go).Start();// 启动t线程,执行Go方法}void HandleUnHandledException(object sender, UnhandledExceptionEventArgs eventArgs){_testOutputHelper.WriteLine("我发现异常了");}
并非所有线程上的异常都需要处理 , 以下情况,.NET Framework 会为你处理:
- 异步委托(APM)
- BackgroundWorker(EAP)
- 任务并行库(TPL)
有两个方式可以实现强行结束:中断、中止
中断(Interrupt)在一个阻塞线程上调用
Thread.Interrupt
会强制释放它 , 并抛出ThreadInterruptedException
异常,与上文的一样 , 这个异常同样不会抛出var t = new Thread(delegate(){try{Thread.Sleep(Timeout.Infinite);// 无期限休眠}catch (ThreadInterruptedException){_testOutputHelper.WriteLine("收到中断信号");}_testOutputHelper.WriteLine("溜溜球~");});t.Start();Thread.Sleep(3000);// 睡3s后中断线程tt.Interrupt();
如果在非阻塞线程上调用Thread.Interrupt
,线程会继续执行直到下次被阻塞时,抛出ThreadInterruptedException
。这避免了以下这样的代码:if ((worker.ThreadState & ThreadState.WaitSleepJoin) > 0)// 线程不安全的{worker.Interrupt();}
??随意中断一个线程是极度危险的,这可能导致调用栈上的任意方法(框架、第三方包)收到意外的中断,而不仅仅是你自己的代码!只要调用栈上发生阻塞(因为使用同步构造) , 中断就会发生在这,如果在设计时没有考虑中断(在finally块中执行适当清理),线程中的对象就可能成为一个奇怪状态(不可用或未完全释放) 。??如果是自己设计的阻塞,完全可以用 信号构造(signal structure) 或者 取消令牌(cancellation tokens) 来达到相同效果,且更加安全 。如果希望结束他人代码导致的阻塞,Abort总是更合适
中止(Abort)通过Thread.Abort方法也可以使阻塞的线程被强制释放,效果和调用Interrupt类似 , 不同的是它抛出的是ThreadAbortException的异常 。另外,这个异常会在catch块结束时被重新抛出(试图更好的结束线程) 。
Thread t = new Thread(delegate(){try{while (true){}}catch (ThreadAbortException){_testOutputHelper.WriteLine("收到中止信号");}// 这里仍然会继续抛出ThreadAbortException , 以保证此线程真正中止});_testOutputHelper.WriteLine(t.ThreadState.ToString()); // Unstarted 状态t.Start();Thread.Sleep(1000);_testOutputHelper.WriteLine(t.ThreadState.ToString()); // Running 状态t.Abort();_testOutputHelper.WriteLine(t.ThreadState.ToString()); // AbortRequested 状态t.Join();_testOutputHelper.WriteLine(t.ThreadState.ToString()); // Stopped 状态
除非Thread.ResetAbort在catch块中被调用,在此之前,线程状态(thread state) 是AbortRequested,调用Thread.ResetAbort来阻止异常被自动重新抛出之后,线程重新进入Running状态(从这开始,它可能被再次中止)static void Main(){Thread t = new Thread (Work);t.Start();Thread.Sleep (1000); t.Abort();Thread.Sleep (1000); t.Abort();Thread.Sleep (1000); t.Abort();}static void Work(){while (true){try { while (true); }catch (ThreadAbortException) { Thread.ResetAbort(); }Console.WriteLine ("我没死!");}}
Thread.Abort在NET 5被弃用了:https://learn.microsoft.com/zh-cn/dotnet/core/compatibility/core-libraries/5.0/thread-abort-obsolete未处理的ThreadAbortException是仅有的两个不会导致应用程序关闭的异常之一 , 另一个是AppDomainUnloadException 。Abort几乎对处于任何状态的线程都有效:Running、Blocked、Suspended以及Stopped 。然而,当挂起的线程被中止时,会抛出ThreadStateException异常 。中止会直到线程之后恢复时才会起作用 。
try { suspendedThread.Abort(); }catch (ThreadStateException) { suspendedThread.Resume(); }// 现在 suspendedThread 才会中止
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 云原生之旅 - 11)基于 Kubernetes 动态伸缩 Jenkins Build Agents
- go GMP
- iphone13出来12会降价吗_iphone13出来12能便宜多少
- 苹果13mini屏幕多大尺寸_苹果13mini屏幕尺寸
- 618红米k40pro会降价吗_618红米k40pro能便宜多少
- 我的世界漏斗与漏斗之间怎么相连(我的世界漏斗上怎么放东西)
- 洛谷 P4135 作诗 题解
- 明日方舟泳装皮肤多少源石头
- 电脑垫多高颈椎最舒服_显示器抬高多少厘米合适
- iqoo7支持无线充电吗_iqoo7电池容量是多少