UncaughtExceptionHandler—处理Runnable线程内的非受检异常
2017-04-21 10:54
417 查看
学过Java多线程的伙伴们都知道,Java入门的多线程方案就是Thread类和Runnable类。如下:
这是Java的基础内容,在此不再赘述。不知道的伙伴可以参见我之前的博客,今天我们要说的是线程内部的异常处理。
Java的异常非为受检异常和非受检异常。由于在多线程中,run()方法无法继续向上显式抛出异常。所以这就使得Thread线程中的异常处理变得棘手。
首先对于受检异常,其应对办法非常通用:就是直接在run()方法体中捕获异常,然后进行对应的处理。对于非受检异常,JVM会帮助我们捕获到。那么我们如何处理JVM捕获的异常呢?答案是Thread.UncaughtExceptionHandler类。正如JDK文档所介绍的一样:
“当一个线程由于发生了非受检异常而终止时,JVM会使用Thread.gerUncaughtExceptionHandler()方法查看该线程上的UncaughtExceptionHandler,并调用他的uncaughtException()方法”——翻译自JDK7 API文档。
下面我们来尝试使用hread.UncaughtExceptionHandler类,来处理线程内部的非受检异常(受检异常直接在run()方法体内部的catch子句中处理)。
public class Demo { public static void main(String[] args) { fun1(); fun2(); } public static void fun1() { Thread thread = new Thread() { @Override public void run() { System.out.println("fun1-thread"); } }; thread.start(); } public static void fun2() { Thread thread = new Thread() { @Override public void run() { System.out.println("fun2-thread"); } }; thread.start(); } }
这是Java的基础内容,在此不再赘述。不知道的伙伴可以参见我之前的博客,今天我们要说的是线程内部的异常处理。
Java的异常非为受检异常和非受检异常。由于在多线程中,run()方法无法继续向上显式抛出异常。所以这就使得Thread线程中的异常处理变得棘手。
首先对于受检异常,其应对办法非常通用:就是直接在run()方法体中捕获异常,然后进行对应的处理。对于非受检异常,JVM会帮助我们捕获到。那么我们如何处理JVM捕获的异常呢?答案是Thread.UncaughtExceptionHandler类。正如JDK文档所介绍的一样:
“当一个线程由于发生了非受检异常而终止时,JVM会使用Thread.gerUncaughtExceptionHandler()方法查看该线程上的UncaughtExceptionHandler,并调用他的uncaughtException()方法”——翻译自JDK7 API文档。
下面我们来尝试使用hread.UncaughtExceptionHandler类,来处理线程内部的非受检异常(受检异常直接在run()方法体内部的catch子句中处理)。
import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; /** * Created by yizhen on 2017/1/7. */ public class Demo { private static final AtomicInteger num = new AtomicInteger(); public static void main(String[] args) throws InterruptedException { final Thread thread = new Thread(new ThreadTask()); //此处使用thread.setUncaughtExceptionHandler(new ThreadExceptionHandler)可以代替ThreadTask中 //的Thread.currentThread().setUncaughtExceptionHandler(new ThreadExceptionHandler(),但这样不好 thread.start(); } private static final class ThreadExceptionHandler implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("One uncaught exception was got:"); System.out.println("Thread id=" + t.getId()); System.out.println("Thread name=" + t.getName()); e.printStackTrace(System.out); // 当捕获到非受检异常时,可以断定原来的线程已经被JVM终止。 // 此时可以新建一个线程继续执行原来的任务 if (num.get() < 5) { new Thread(new ThreadTask()).start(); } } } private static final class ThreadTask implements Runnable { @Override public void run() { num.incrementAndGet(); Thread.currentThread().setUncaughtExceptionHandler(new ThreadExceptionHandler());//设置非受检异常的ExceptionHandler try { for (int i = 4; i >= 0; i--) { TimeUnit.SECONDS.sleep(1); // 当i=0时候抛出的非受检异常,将导致当前线程被JVM杀死 // 但异常会被在上面设置的ThreadExceptionHandler捕获到,进而被处理 System.out.println(12 / i); } } catch (InterruptedException e) {//受检异常直接在run方法体内部处理 e.printStackTrace(); } } } }
上面的代码不难理解,在主函数中,我们执行了一个Thread线程,这个线程中执行ThreadTask任务。在ThreadTask任务的实现中,如果是受检异常,直接在run()方法体中处理。对于非受检异常,我们在run()方法体的开头设置了非受检异常处理类ThreadExceptionException,这个类的uncaughtException()方法就是处理线程内部非捕获异常的具体执行者。该方法会判断任务执行的次数,如果没有超过5次,就会创建一个Thread线程来重新执行任务(读者要清楚,一旦一个线程抛出了非受检异常,JVM就会把它杀死,然后把捕获到的非受检异常传递给UncaughtExceptionHandler类对象类处理)。
一定有读者会问,如果没有通过setUncaughtExceptionHandler()方法设置Handler怎么办?这个问题在JDK API中给了回答:
“如果一个线程没有显式的设置它的UncaughtExceptionHandler,JVM就会检查该线程所在的线程组是否设置了UncaughtExceptionHandler,如果已经设置,就是用该UncaughtExceptionHandler;否则查看是否在Thread层面通过静态方法setDefaultUncaughtExceptionHandler()设置了UncaughtExceptionHandler,如果已经设置就是用该UncaughtExceptionHandler;如果上述都没有找到,JVM会在对应的console中打印异常的堆栈信息。”——翻译自JDK7 API文档
/** * Created by yizhen on 2017/1/7. */ public class Demo { public static void main(String[] args) throws InterruptedException { Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("static thread exception handler -- " + t.getName()); } }); final Thread t1 = new Thread(new ThreadTaskWithHandler(), "t1"); t1.start(); final Thread t2 = new Thread(new ThreadTaskNoHandler(), "t2"); t2.start(); } private static final class ThreadExceptionHandler implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("explicit exception handler -- " + t.getName()); } } private static final class ThreadTaskWithHandler implements Runnable { @Override public void run() { Thread.currentThread().setUncaughtExceptionHandler(new ThreadExceptionHandler()); System.out.println(12 / 0); } } private static final class ThreadTaskNoHandler implements Runnable { @Override public void run() { System.out.println(12 / 0); } } }从上面的程序可以看到,t1线程的非受检异常始终会被explicit exception handler捕获到,而t2线程的非受检异常始终会被static thread exception handler捕获到。
至此,Thread线程内的异常处理就介绍完了,这包括受检异常和非受检异常。细心的读者会发现,本文仅仅涉及Thread和Runnable的多线程体系。在Java中,还有Executor和Callable的多线程体系。那关于这个体系的异常如何处理呢?笔者会后续博文中介绍!
相关文章推荐
- 全局异常处理UncaughtExceptionHandler
- Android捕获异常处理——UncaughtExceptionHandler
- Android中使用UncaughtExceptionHandler来处理未捕获的异常
- Java异常处理之处理未捕获的异常及UncaughtExceptionHandler的使用
- 用Thread中的UncaughtExceptionHandler来处理未捕获的异常
- NSSetUncaughtExceptionHandler处理异常
- UncaughtExceptionHandler 捕获异常线程以及出现异常重启
- JAVA多线程之UncaughtExceptionHandler,处理非正常的线程中止
- android应用开发-------------应用崩溃全局异常捕获处理(UncaughtExceptionHandler)
- java UncaughtExceptionHandler 处理线程意外中止
- java多线程中unchecked 异常的处理UncaughtExceptionHandler
- Java基础---java线程unchecked异常的处理UncaughtExceptionHandler
- Android异常处理——UncaughtExceptionHandler捕获全局异常
- Java多线程中异常的处理UncaughtExceptionHandler
- JDK5_Thread的run异常的setUncaughtExceptionHandler处理
- Thinking in Java学习笔记 Thread.UncaughtExceptionHandler接口实现捕获线程内异常
- iOS —— 发布应用的异常信息捕获和处理 NSSetUncaughtExceptionHandler()
- java多线程中unchecked 异常的处理UncaughtExceptionHandler
- Android 全局异常处理之UncaughtExceptionHandler
- java UncaughtExceptionHandler 处理线程意外中止