在java多線程程序中,全部線程都不容許拋出未捕獲的checked exception(好比sleep時的InterruptedException),也就是說各個線程須要本身把本身的checked exception處理掉。java
這句話怎麼理解,最簡單的看下圖,也就是不能在Runnable的run方法上拋出異常,必須在裏面捕獲。多線程
這一點是經過java.lang.Runnable.run()方法聲明(由於此方法聲明上沒有throw exception部分)進行了約束。可是線程依然有可能拋出unchecked exception(如運行時異常),當此類異常跑拋出時,線程就會終結,而對於主線程和其餘線程徹底不受影響,且徹底感知不到某個線程拋出的異常(也是說徹底沒法catch到這個異常)。JVM的這種設計源自於這樣一種理念:「線程是獨立執行的代碼片段,線程的問題應該由線程本身來解決,而不要委託到外部。」基於這樣的設計理念,在Java中,線程方法的異常(不管是checked仍是unchecked exception),都應該在線程代碼邊界以內(run方法內)進行try catch並處理掉.換句話說,咱們不能捕獲從線程中逃逸的異常。ide
看下面的例子:spa
public class ExceptionTest { public static void main(String[] args) { try { new Thread(new ExceptionTask()).start(); } catch (Exception e) { System.out.println("注意看我是否能打印。。。"); e.printStackTrace(); } } } class ExceptionTask implements Runnable { @Override public void run() { System.out.println("".substring(0, 10)); } }
打印結果線程
Exception in thread "Thread-0" java.lang.StringIndexOutOfBoundsException: String index out of range: 10 at java.lang.String.substring(Unknown Source) at com.actuator.ExceptionTask.run(ExceptionTest.java:21) at java.lang.Thread.run(Unknown Source)
從運行結果中,咱們能夠看到的是,"Thread-0"線程裏的異常在main線程中沒有catch到。設計
問題來了,咱們若是須要捕獲"Thread-0"線程的unchecked異常時該怎麼辦?Java SE5以後,咱們能夠經過Executor來解決這個問題。code
Thread.UncaughtExceptionHandler是java SE5中的新接口,它容許咱們在每個Thread對象上添加一個異常處理器。(UncaughtExceptionHandler)。Thread.UncaughtExceptionHandler.uncaughtException()方法會在線程因未捕獲的異常而面臨死亡時被調用。對象
下面這個例子簡單的演示瞭如何使用UncaughtExceptionHandler。blog
import java.lang.Thread.UncaughtExceptionHandler; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; public class ExceptionTest { public static void main(String[] args) { // 下面有兩種方式來執行線程 // 第一種,非線程池寫法 Thread t = new Thread(new ExceptionTask()); t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("線程"+t.getName()+"捕獲到異常:"+e.getMessage()); } }); t.start(); // 第二種,線程池寫法 ExecutorService executorService = Executors.newCachedThreadPool(new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("線程"+t.getName()+"捕獲到異常:"+e.getMessage()); } }); return t; } }); executorService.execute(new ExceptionTask()); } } class ExceptionTask implements Runnable { @Override public void run() { System.out.println("".substring(0, 10)); } }
兩個執行結果同樣接口
線程Thread-0捕獲到異常:String index out of range: 10