新建執行緒的異常處理
阿新 • • 發佈:2019-01-04
將Thinking injava 12.2.14節進行總結
一般情況:
由於執行緒的本質特性,使你不能捕獲從執行緒中逃逸的異常。一旦異常逃出任務的run方法,它就會向外傳播到控制檯
package hfi.bellychang.Task.CaptureException.Demo01; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 子執行緒中的異常在主執行緒中是捕捉不到的 * Created by Administrator on 2017/6/26. */ class ExceptionThread implements Runnable { Logger logger = LoggerFactory.getLogger(ExceptionThread.class); ExceptionThread(){ super(); logger.info("exception happens in ExceptionThread"); } @Override public void run() { throw new RuntimeException(); } } public class MainThread { @Test public void test() { ExecutorService exec = Executors.newCachedThreadPool(); exec.execute(new ExceptionThread()); } }
執行結果:異常向外傳播到控制檯
問題自然來了,如何捕捉子執行緒中的異常,使其不直接向外傳播到控制檯呢?
解決方案1:
實現ThreadFactory介面,在newThread方法中附加異常處理器。將這個工廠傳遞給Executors建立新的ExecutorService的方法,就設定了這個執行緒池專有的未捕獲異常的處理器
package hfi.bellychang.Task.CaptureException.Demo02; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; /** * 在主執行緒中捕獲子執行緒產生的異常 * 要修改Executor產生錢程的方式 * Thread.UncaughtExceptionHandler是Java SE5 中的新介面, * 它允許你在每個Thread物件上都附著一個異常處理器o * Thread.UncaughtExceptionHandler。uncaughtException()會線上程因未捕獲的異常而臨近死亡時被呼叫 * * Created by Administrator on 2017/6/26. */ class ExceptionThread2 implements Runnable { public void run() { throw new RuntimeException(); } } class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { Logger logger = LoggerFactory.getLogger(MyUncaughtExceptionHandler.class); @Override public void uncaughtException(Thread t, Throwable e) { logger.info("caught " + e); } } /** * 建立了一個新型別的ThreadFactory, 它將在每個新建立的Thread物件上 * 附著一個Thread.UncaughtExceptionHandler */ class HandlerThreadFactory implements ThreadFactory { Logger logger = LoggerFactory.getLogger(this.getClass()); @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); logger.info("created " + t); //附著一個Thread.UncaughtExceptionHandler t.setUncaughtExceptionHandler( new MyUncaughtExceptionHandler()); return t; } } /** * 示例使得你可以按照具體情況逐個地設定處理器 * 意思是通過不同的ThreadFactory的實現 附著不同的ExceptionHandler? */ public class MainThread { public static void main(String[] args) { //我們將這個工廠傳遞給Executors建立新的ExecutorService的方法: //此執行緒池專有的未捕獲異常處理器 ExecutorService exec = Executors.newCachedThreadPool( new HandlerThreadFactory()); exec.execute(new ExceptionThread2()); } }
執行結果
可見通過不同的ThreadFactory的實現,附著不同的ExceptionHandler,可以按照具體情況逐個地設定處理器
解決方案2:
在Thread類中設定一個靜態域,並將這個處理器設定為Thread類的預設的未捕獲異常處理器 Thread.setDefaultUncaughtExceptionHandler,但這樣不能指定某個Thread使用哪個異常處理器
package hfi.bellychang.Task.CaptureException.Demo03; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 通過這種方式,在主執行緒中捕獲到了子執行緒中的異常 * Created by Administrator on 2017/6/26. */ class ExceptionThread implements Runnable { public void run() { throw new RuntimeException(); } } class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { Logger logger = LoggerFactory.getLogger(this.getClass()); @Override public void uncaughtException(Thread t, Throwable e) { logger.info("caught " + e); } } public class MainThread { public static void main(String[] args) { Thread.setDefaultUncaughtExceptionHandler( new MyUncaughtExceptionHandler()); ExecutorService exec = Executors.newCachedThreadPool(); exec.execute(new ExceptionThread()); } }
通過以上的兩種方式,就可以將異常資訊在catch中寫入日誌檔案,在日誌檔案中檢視子執行緒是否發生異常,對程式的執行情況有所掌握