3Java多线程-处理子线程异常
Posted 6xiong
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了3Java多线程-处理子线程异常相关的知识,希望对你有一定的参考价值。
处理子线程异常(重要)、
参考:https://www.cnblogs.com/jpfss/p/10272066.html
1、Java子线程中的异常处理
父线程中启动子线程,直接在父线程启动子线程的地方try...catch,是捕获不到子线程的异常的
原因:Runnable接口的run方法的完整签名,因为没有标识throws语句,所以方法是不会抛出checked异常的。至于RuntimeException这样的 unchecked异常,由于新线程由JVM进行调度执行,如果发生了异常,也不会通知到父线程。
2、处理子线程的异常
子线程中处理:
a.子线程中try...catch
b.为子线程设置“未捕获异常处理器”UncaughtExceptionHandler
既然a方法已经可以捕获异常,为什么还要有b存在,我的理解是a需要指定可能发生异常的代码,而b不需要指定,只要发生异常,对应的异常处理器自动处理。
父线程中处理:
c.通过Future的get方法捕获异常(推荐)
3、示例代码
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 }
以上是关于3Java多线程-处理子线程异常的主要内容,如果未能解决你的问题,请参考以下文章