由于线程的本质特性,使得你不能捕获从线程中逃逸的异常,一旦异常逃出run()方法,他就会向外传播到控制台。除非采取特殊的步骤去捕获这种错误的异常,在JDK1.5以前,可以只用线程组来捕获,但在这之后,可以使用Executor来解决这个问题,下面示例如下:
package tij; /** * Created by huaox on 2017/4/19. * */ public class ExceptionThread implements Runnable{ @Override public void run() { throw new RuntimeException("haha"); } public static void main(String[] args) { //try { Thread thread = new Thread(new ExceptionThread()); thread.start(); //}catch (Exception e){ // System.out.println("a "+e.getLocalizedMessage()); //} } }
输出结果:
Exception in thread "Thread-0" java.lang.RuntimeException: haha at tij.ExceptionThread.run(ExceptionThread.java:10) at java.lang.Thread.run(Thread.java:745) Process finished with exit code 0
如果加上try..catch也不能捕获跨线程的异常。
package tij; /** * Created by huaox on 2017/4/19. * */ public class ExceptionThread implements Runnable{ @Override public void run() { throw new RuntimeException("haha"); } public static void main(String[] args) { try { Thread thread = new Thread(new ExceptionThread()); thread.start(); }catch (Exception e){ System.out.println("a "+e.getLocalizedMessage()); } } }
输出结果:
Exception in thread "Thread-0" java.lang.RuntimeException: haha at tij.ExceptionThread.run(ExceptionThread.java:10) at java.lang.Thread.run(Thread.java:745) Process finished with exit code 0
与上面一样,加不加try...catch的效果时一样的。为了解决上述问题可以使用Thread.UncaughtExceptionHandle,这是1.5中的新接口。它允许每个Thread对象上都赋予一个线程i异常处理器。
Thread.UncaughtExceptionHandle.uncaughtException()方法会在线程因未捕获的异常而临近死亡的时候调用。代码如下:
package tij; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; /** * Created by huaox on 2017/4/19. * */ class ThreadExp implements Runnable{ @Override public void run() { Thread t = Thread.currentThread(); System.out.println("run() by "+t); System.out.println("eh = "+t.getUncaughtExceptionHandler()); throw new RuntimeException(); } } //定义异常处理器 class MyUncaughtException implements Thread.UncaughtExceptionHandler{ @Override public void uncaughtException(Thread t, Throwable e) { System.out.println(t +" caught "+e); } } //定义线程工厂 class MyThreadFactory implements ThreadFactory{ @Override public Thread newThread(Runnable r) { System.out.println(this +" creating new Thread"); Thread thread = new Thread(r); System.out.println("created: "+thread); thread.setUncaughtExceptionHandler(new MyUncaughtException()); System.out.println("eh= "+thread.getUncaughtExceptionHandler()); return thread; } } public class ExceptionThread2{ public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(new MyThreadFactory()); executorService.execute(new ThreadExp()); } }
输出结果:
tij.MyThreadFactory@74a14482 creating new Thread created: Thread[Thread-0,5,main] eh= tij.MyUncaughtException@1540e19d run() by Thread[Thread-0,5,main] eh = tij.MyUncaughtException@1540e19d tij.MyThreadFactory@74a14482 creating new Thread created: Thread[Thread-1,5,main] eh= tij.MyUncaughtException@655a2155 Thread[Thread-0,5,main] caught java.lang.RuntimeException Process finished with exit code 0
现在可以看到未捕获的线程通过UncaughtExceptionHandler进行处理的。上面的这个示例使得你可以按照具体情况逐个的设置处理器,如果想设置全局处理器,那么在Thread中设置一个静态域即可,并且这个将作为默认处理器,例如;
package tij; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * Created by huaox on 2017/4/19. * */ public class ExceptionThread implements Runnable{ @Override public void run() { throw new RuntimeException("haha"); } public static void main(String[] args) { Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtException()); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(new ExceptionThread()); executorService.shutdownNow(); } }
输出结果:
Thread[pool-1-thread-1,5,main] caught java.lang.RuntimeException: haha
Process finished with exit code 0
这个处理器只有在不存在专有的未捕获异常处理器的情况下才会调用,系统会检查线程的专有版本,如果没有发现,则检查线程组是否有uncaughtException()方法,如果也没有,再来调用全局的处理
函数