1.需要UncaughtExceptionHandler的理由
主线程中可以很方便地发现异常,如打印堆栈信息,而子线程不能,代码示例如ExceptionInChildThread类所示。子线程无法用传统的try catch方式捕获异常,代码示例如CannotCatchDirectly类所示。不捕获异常的话,子线程抛出异常停止运行,破坏系统的健壮性。 /** * 描述:研究单线程抛出时的处理情况 */ public class ExceptionInChildThread implements Runnable { @Override public void run() { throw new RuntimeException(); } public static void main(String[] args) { ExceptionInChildThread exceptionInChildThread = new ExceptionInChildThread(); Thread thread = new Thread(exceptionInChildThread); thread .start(); for (int i = 1; i < 10; i++) { System.out.println("正在打印" + i); } } }程序执行结果如下所示,可以看到堆栈信息被散乱输出到控制台,不是很便利。
Exception in thread "Thread-0" java.lang.RuntimeException 正在打印1 正在打印2 at com.leichuangkj.threads.ExceptionInChildThread.run(ExceptionInChildThread.java:6) 正在打印3 at java.lang.Thread.run(Thread.java:748) 正在打印4 正在打印5 正在打印6 正在打印7 正在打印8 正在打印9 /** * 描述:证明线程的异常不能用传统方法捕获 * 1.不加try catch抛出4个异常,都带线程名字 * 2.加了try catch,期望捕获到第一个线程的异常,线程234不应该被捕获,期待打印出Caught Exception * 3.执行时发现,根本没有Caught Exception,线程234依然运行并且抛出异常 */ public class CannotCatchDirectly implements Runnable { @Override public void run() { throw new RuntimeException(); } public static void main(String[] args) throws InterruptedException { CannotCatchDirectly cannotCatchDirectly = new CannotCatchDirectly(); try { Thread thread1 = new Thread(cannotCatchDirectly, "Thread1"); thread1.start(); Thread.sleep(1000); Thread thread2 = new Thread(cannotCatchDirectly, "Thread2"); thread2.start(); Thread.sleep(1000); Thread thread3 = new Thread(cannotCatchDirectly, "Thread3"); thread3.start(); Thread.sleep(1000); Thread thread4 = new Thread(cannotCatchDirectly, "Thread4"); thread4.start(); Thread.sleep(1000); } catch (RuntimeException exception) { System.out.println(Thread.currentThread().getName() + "抛出异常"); } } }程序执行结果如下所示,当Thread1抛出异常时,应当进入catch分支,并终止程序运行。但实际上没有,程序继续运行,4个子线程分别抛出异常,这说明使用try catch没有捕获到子线程异常。
Exception in thread "Thread1" java.lang.RuntimeException at com.leichuangkj.threads.CannotCatchDirectly.run(CannotCatchDirectly.java:6) at java.lang.Thread.run(Thread.java:748) Exception in thread "Thread2" java.lang.RuntimeException at com.leichuangkj.threads.CannotCatchDirectly.run(CannotCatchDirectly.java:6) at java.lang.Thread.run(Thread.java:748) Exception in thread "Thread3" java.lang.RuntimeException at com.leichuangkj.threads.CannotCatchDirectly.run(CannotCatchDirectly.java:6) at java.lang.Thread.run(Thread.java:748) Exception in thread "Thread4" java.lang.RuntimeException at com.leichuangkj.threads.CannotCatchDirectly.run(CannotCatchDirectly.java:6) at java.lang.Thread.run(Thread.java:748)2.UncaughtExceptionHandler源码分析
public class ThreadGroup implements Thread.UncaughtExceptionHandler { public void uncaughtException(Thread t, Throwable e) { //默认情况下parent是null if (parent != null) { parent.uncaughtException(t, e); } else { //设置全局handler进行处理 Thread.UncaughtExceptionHandler ueh = Thread.getDefaultUncaughtExceptionHandler(); if (ueh != null) { ueh.uncaughtException(t, e); } else if (!(e instanceof ThreadDeath)) { //全局handler不存在则输出异常堆栈 System.err.print("Exception in thread \"" + t.getName() + "\" "); e.printStackTrace(System.err); } } } }3.全局异常处理器
/** * 描述:自定义UncaughtExceptionHandler */ public class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { private String name; MyUncaughtExceptionHandler(String name){ this.name = name; } @Override public void uncaughtException(Thread t, Throwable e) { System.out.println(t.getName() + "捕获异常,异常信息" + e.toString()); } } /** * 描述:使用自定义的UncaughtExceptionHandler */ class UseOwnUncaughtExceptionHandler implements Runnable { @Override public void run() { throw new RuntimeException(); } public static void main(String[] args) throws InterruptedException { Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler("捕获器")); UseOwnUncaughtExceptionHandler useOwnUncaughtExceptionHandler = new UseOwnUncaughtExceptionHandler(); Thread thread1 = new Thread(useOwnUncaughtExceptionHandler, "Thread1"); thread1.start(); Thread.sleep(1000); Thread thread2 = new Thread(useOwnUncaughtExceptionHandler, "Thread2"); thread2.start(); Thread.sleep(1000); Thread thread3 = new Thread(useOwnUncaughtExceptionHandler, "Thread3"); thread3.start(); Thread.sleep(1000); Thread thread4 = new Thread(useOwnUncaughtExceptionHandler, "Thread4"); thread4.start(); Thread.sleep(1000); } }程序执行结果如下所示,4个子线程抛出的异常都被捕获。
Thread1捕获异常,异常信息java.lang.RuntimeException Thread2捕获异常,异常信息java.lang.RuntimeException Thread3捕获异常,异常信息java.lang.RuntimeException Thread4捕获异常,异常信息java.lang.RuntimeException