三、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 }
相關文章
相關標籤/搜索