父线程捕获子线程的异常方式
如果 子线程出现异常问题 如果不在父线程中进行捕获异常 该子线程也不进行异常捕获的话 则子线程一但出现异常 则此子线程就关闭了,父线程并不知情,可能认为该子线程已经正常、运行完毕了呢,所以突显出父线程捕获子线程异常状态的重要性。在普通的单线程程序中,捕获异常只需要通过try ... catch ... finally ...代码块就可以了。那么在并发情况下,比如在父线程中启动了子线程,如何在父线程中捕获子线程中的异常,从而进行相应的处理呢?为线程设置异常处理器。具体做法有一下两种:
(1)Thread.setUncaughtExceptionHandler设置当前线程的异常处理器;
(2)Thread.setDefaultUncaughtExceptionHandler为整个程序设置默认的异常处理器;
线程出现异常,如果当前线程有异常处理器(默认没有),则优先使用该线程的异常处理器,否则,如果当前线程所属的线程组存在异常处理器,则使用线程组的异常处理器;否则,使用全局默认的DefaultUncaughtExceptionHandler;如果都没有的话,子线程就会退出。
1.设置当前线程的异常处理器
package com.example.springbootstudy.test.exception; public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { public void uncaughtException(Thread t, Throwable e) { System.out.println("MyUncaughtExceptionHandler do something..."); System.out.println("errorMsg:" + e.getMessage()); } }
package com.example.springbootstudy.test.exception; public class ChildTask implements Runnable { public void run() { Thread.currentThread().setUncaughtExceptionHandler(new MyUncaughtExceptionHandler()); System.out.println("do something"); throw new RuntimeException("ChildTask异常"); } public static void main(String[] args) { Thread t= new Thread(new ChildTask()); t.start(); } }
程序运行结果如下所示:
do something
MyUncaughtExceptionHandler do something...
errorMsg:ChildTask异常
2、设置默认异常处理器
package com.example.springbootstudy.test.exception; public class AppTest { public static void main(String[] args) { Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler()); Thread t= new Thread(new ChildTask()); t.start(); } } class ChildTask2 implements Runnable { public void run() { System.out.println("do something"); throw new RuntimeException("ChildTask异常"); } }
3、Future的get
使用线程池提交一个能获取到返回信息的方法,也就是ExecutorService.submit(Callable) 在submit之后可以获得一个线程执行结果的Future对象,而如果子线程中发生了异常,通过future.get()获取返回值时,可以捕获到 ExecutionException异常,从而知道子线程中发生了异常。
1 package com.example.springbootstudy.test.exception; 2 3 import java.util.concurrent.*; 4 5 public class childTask2 { 6 7 public static void main(String[] args) { 8 System.out.println("main..."); 9 ExecutorService executorService = Executors.newCachedThreadPool(); 10 Future<String> future = executorService.submit(new App()); 11 try { 12 String s = future.get(); 13 } catch (InterruptedException e) { 14 System.out.println("InterruptedException"); 15 } catch (ExecutionException e) { 16 System.out.println(e.getMessage()); 17 } 18 } 19 } 20 21 22 class App implements Callable<String> { 23 24 @Override 25 public String call() throws Exception { 26 System.out.println("do something"); 27 throw new Exception("ChildTask2异常"); 28 } 29 30 }
总结:以上是三种父线程获取子线程的异常总结。
郭慕荣博客园