三、Java多线程-处理子线程异常

处理子线程异常(重要)、
参考:https://www.cnblogs.com/jpfss/p/10272066.html
一、Java子线程中的异常处理
  父线程中启动子线程,直接在父线程启动子线程的地方try...catch,是捕获不到子线程的异常的
  缘由:Runnable接口的run方法的完整签名,由于没有标识throws语句,因此方法是不会抛出checked异常的。至于RuntimeException这样的 unchecked异常,因为新线程由JVM进行调度执行,若是发生了异常,也不会通知到父线程。
二、处理子线程的异常
  子线程中处理:
    a.子线程中try...catch
    b.为子线程设置“未捕获异常处理器”UncaughtExceptionHandler
    既然a方法已经能够捕获异常,为何还要有b存在,个人理解是a须要指定可能发生异常的代码,而b不须要指定,只要发生异常,对应的异常处理器自动处理。
  父线程中处理:
    c.经过Future的get方法捕获异常(推荐)html

三、示例代码java

 1 import java.util.ArrayList;  2 import java.util.List;  3 import java.util.concurrent.Callable;  4 import java.util.concurrent.ExecutionException;  5 import java.util.concurrent.ExecutorService;  6 import java.util.concurrent.Executors;  7 import java.util.concurrent.Future;  8 
 9 public class TestExceptionThred {  10     
 11     /**
 12  * @param args  13      */
 14     public static void main(String[] args) {  15         ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(5);  16         List<Future<String>> fetrueResult = new ArrayList<>();  17         System.out.println("start");  18         
 19         try {  20             System.out.println("ssssssss");  21 // newFixedThreadPool.execute(new ChildThread01());  22 // newFixedThreadPool.execute(new ChildThread01());  23 // newFixedThreadPool.execute(new ChildThread01());  24 
 25 // newFixedThreadPool.execute(new ChildThread0101());  26 // newFixedThreadPool.execute(new ChildThread0101());  27 
 28 // newFixedThreadPool.execute(new ChildThread02());  29 // newFixedThreadPool.execute(new ChildThread02());  30 
 31 // newFixedThreadPool.execute(new ChildThread0202());  32 // newFixedThreadPool.execute(new ChildThread0202());
 33             
 34             Future<String> result01 = newFixedThreadPool.submit(new ChildThread03());  35  fetrueResult.add(result01);  36             Future<String> result02 = newFixedThreadPool.submit(new ChildThread03());  37  fetrueResult.add(result02);  38             for (Future<String> result : fetrueResult) {  39  result.get();  40  }  41             System.out.println("eeeeeeeee");  42         } catch (InterruptedException | ExecutionException e) {  43             System.out.println("InterruptedException or ExecutionException has been handled");  44         } catch (Exception e) {  45             System.out.println("exception has been handled");  46         } finally {  47             System.out.println("finally");  48             if (null != newFixedThreadPool) {  49  newFixedThreadPool.shutdown();  50  }  51  }  52         System.out.println("end");  53  }  54     
 55 }  56 
 57 /**
 58  * 子线程中发生异常,未处理直接抛出,这种状况下,子线程直接退出,且不会记录任何日志  59  */
 60 class ChildThread01 implements Runnable {  61     
 62     /*
 63  * @see java.lang.Runnable#run()  64      */
 65  @Override  66     public void run() {  67         System.out.println("ChildThread before exception");  68  exceptionMethod();  69         System.out.println("ChildThread before exception");  70  }  71     
 72     private void exceptionMethod() {  73         throw new RuntimeException("ChildThread01 exception");  74  }  75 }  76 
 77 /**
 78  * 解决方案1:在子线程中try...catch捕获异常  79  * 子线程中发生异常,并在子线程中处理  80  */
 81 /**
 82  * 为线程设置异常处理器。具体作法能够是如下几种:  83  * (1)Thread.setUncaughtExceptionHandler设置当前线程的异常处理器;  84  * (2)Thread.setDefaultUncaughtExceptionHandler为整个程序设置默认的异常处理器;  85  * 若是当前线程有异常处理器(默认没有),则优先使用该UncaughtExceptionHandler类;  86  * 不然,若是当前线程所属的线程组有异常处理器,则使用线程组的UncaughtExceptionHandler;  87  * 不然,使用全局默认的DefaultUncaughtExceptionHandler;若是都没有的话,子线程就会退出。  88  * 注意:子线程中发生了异常,若是没有任何类来接手处理的话,是会直接退出的,而不会记录任何日志。  89  * 因此,若是什么都不作的话,是会出现子线程任务既没执行成功,也没有任何日志提示的“诡异”现象的。  90  */
 91 class ChildThread0101 implements Runnable {  92     
 93     /*
 94  * @see java.lang.Runnable#run()  95      */
 96  @Override  97     public void run() {  98         //可能发生异常的地方,用try...catch处理
 99         try { 100             System.out.println("ChildThread0101 before exception"); 101  exceptionMethod(); 102             System.out.println("ChildThread0101 before exception"); 103         } catch (Exception e) { 104             System.out.println("exception has been handled in ChildThread0101"); 105  } 106  } 107     
108     private void exceptionMethod() { 109         throw new RuntimeException("ChildThread0101 exception"); 110  } 111 } 112 
113 /**
114  * 解决方案2:为子线程设置“未捕获异常处理器”UncaughtExceptionHandler 115  * 子线程中发生异常,并在子线程中处理 116  */
117 class ChildThread02 implements Runnable { 118     private static ChildThreadExceptionHandler exceptionHandler; 119     
120     static { 121         exceptionHandler = new ChildThreadExceptionHandler(); 122  } 123     
124  @Override 125     public void run() { 126         //下面代码可能会发生异常,可是不须要用try...catch显示的包裹代码处理, 127         //定义的异常处理器会自动捕获异常,并在子线程中处理 128         
129         //设置当前线程的异常处理器
130  Thread.currentThread().setUncaughtExceptionHandler(exceptionHandler); 131         System.out.println("ChildThread02 do something 1"); 132  exceptionMethod(); 133         System.out.println("ChildThread02 do something 2"); 134  } 135     
136     private void exceptionMethod() { 137         throw new RuntimeException("ChildThread02 exception"); 138  } 139     
140     //为线程设置“未捕获异常处理器”UncaughtExceptionHandler
141     public static class ChildThreadExceptionHandler implements Thread.UncaughtExceptionHandler { 142         public void uncaughtException(Thread t, Throwable e) { 143             System.out.println(String.format("handle exception in ChildThread02. %s", e)); 144  } 145  } 146 } 147 
148 /**
149  * 解决方案2 150  * 子线程中发生异常,并在子线程中处理 151  */
152 class ChildThread0202 implements Runnable { 153     private static ChildThreadExceptionHandler exceptionHandler; 154     
155     static { 156         exceptionHandler = new ChildThreadExceptionHandler(); 157         //设置全部线程的默认异常处理器
158  Thread.setDefaultUncaughtExceptionHandler(exceptionHandler); 159  } 160     
161     public void run() { 162         System.out.println("ChildThread0202 do something 1"); 163  exceptionMethod(); 164         System.out.println("ChildThread0202 do something 2"); 165  } 166     
167     private void exceptionMethod() { 168         throw new RuntimeException("ChildThread0202 exception"); 169  } 170     
171     public static class ChildThreadExceptionHandler implements Thread.UncaughtExceptionHandler { 172         public void uncaughtException(Thread t, Throwable e) { 173             System.out.println(String.format("handle exception in ChildThread0202. %s", e)); 174  } 175  } 176 } 177 
178 /**
179  * 解决方案3:经过Future的get方法捕获异常(推荐) 180  */
181 /**
182  * 使用线程池提交一个能获取到返回信息的方法,也就是ExecutorService.submit(Callable) 183  * 在submit以后能够得到一个线程执行结果的Future对象,而若是子线程中发生了异常, 184  * 经过future.get()获取返回值时,能够捕获到ExecutionException异常,从而知道子线程中发生了异常 185  * 186  * 注意,若是不调用future.get(),则不会捕获到异常;若是子线程发生异常,直接退出,无任何记录 187  * 若是启动了多个子线程,捕获到任何一个子线程的异常,父线程执行finally语句或执行后续代码 188  */
189 class ChildThread03 implements Callable<String> { 190     public String call() throws Exception { 191         System.out.println("ChildThread03 do something 1"); 192  exceptionMethod(); 193         System.out.println("ChildThread03 do something 2"); 194         return "ChildThread03 test result"; 195  } 196     
197     private void exceptionMethod() { 198         throw new RuntimeException("ChildThread03 exception"); 199  } 200 }
相关文章
相关标签/搜索