首页 / 操作系统 / Linux / Java Thread线程异常监控
一、场景描述:单线程程序可以用try...catch捕获程序的异常,而在多线程程序的时候是无法使用try...catch捕获。示例1:多线程发生异常,无法使用try...catch捕获问题public class NoCaughtThreadimplements Runnable{@Overridepublic void run() {System.out.println(3 / 2);System.out.println(3 / 0);System.out.println(3 / 1);}public static void main(String[] args) {try {Thread thread = new Thread(new NoCaughtThread());thread.start();} catch (Exception e) {System.out.println("==Exception: " + e.getMessage());}}} 运行结果:1
Exception in thread "Thread-0" java.lang.ArithmeticException: / by zero
at threadtest.NoCaughtThread.run(NoCaughtThread.java:7)
at java.lang.Thread.run(Thread.java:724)显然这并非程序设定异常捕获,此时try...catch无法捕获线程的异常。此时,如果线程因为异常而终止执行将无法检测到异常。究其原因Thread类run()方法是不抛出任何检查型异常的,而自身却可能因为一个异常而被中止。二、解决方式大致有两种:① 在run()中设置对应的异常处理,主动方法来解决未检测异常;② Thread类API中提供Interface接口UncaughtExceptionHandler,该接口包含uncaughtException方法,它能检测出某个未捕获的异常而终结的情况;示例2:主动的检测异常import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class InitiativeCaught {public static void main(String[] args) {InitialtiveThread initialtiveThread = new InitialtiveThread() ;ExecutorService exec = Executors.newCachedThreadPool();exec.execute(initialtiveThread);exec.shutdown();}}class InitialtiveThread implements Runnable {@Overridepublic void run() {Throwable thrown = null;try {System.out.println(3 / 2);System.out.println(3 / 0);System.out.println(3 / 1);} catch (Throwable e) {thrown = e;} finally {threadDeal(this, thrown);}}public void threadDeal(Runnable r, Throwable t) {System.out.println("==Exception: " + t.getMessage());}} 运行结果:1
==Exception: / by zero此时是主动捕获异常并做处理,得到想要的结果。示例3:Thread类API中提供UncaughtExceptionHandler接口捕获异常,要求检测线程异常,发生异常设置为重复调用三次之后结束线程。import java.lang.Thread.UncaughtExceptionHandler;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class ThreadMonitor implements Runnable {private int data;// 可设置通过构造传参private int control = 0;private static final int MAX = 3;// 设置重试次数public ThreadMonitor(int i) {this.data = i;}public ThreadMonitor() {// TODO Auto-generated constructor stub}@Overridepublic void run() {Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {@Overridepublic void uncaughtException(Thread arg0, Throwable e) {// TODO Auto-generated method stubSystem.out.println("==Exception: " + e.getMessage());String message = e.getMessage();if( control==MAX ){return ;}else if( "ok".equals(message) ){return ;}else if ( "error".equals(message) ) {new Thread() {public void run() {try {System.out.println("开始睡眠。");Thread.sleep(1 * 1000);control++ ;System.out.println("睡眠结束,control: "+ control);myTask(data) ;} catch (InterruptedException e) {e.printStackTrace();}};}.start();}else{return ;}}});myTask(data) ;}@SuppressWarnings("finally")public void myTask(int data){boolean flag = true ;try {System.out.println(4 / data);} catch (Exception e) {flag = false ;} finally {if( flag ){throw new RuntimeException("ok");}else{throw new RuntimeException("error");}}}public static void main(String[] args) {ExecutorService exec = Executors.newCachedThreadPool();ThreadMonitor threadMonitor = new ThreadMonitor(0);exec.execute(threadMonitor);exec.shutdown();}} 运行结果:==Exception: error
开始睡眠。
睡眠结束,control: 1
==Exception: error
开始睡眠。
睡眠结束,control: 2
==Exception: error
开始睡眠。
睡眠结束,control: 3
==Exception: error此时,可以正常捕获线程因除数为零造成的中断。其中:(1) 在Thread类API中提供Interface接口UncaughtExceptionHandler,该接口包含一个uncaughtException方法,它能检测出某个由于未捕获的异常而终结的情况。定义如下:UncaughtExceptionHandler接口: public static interface Thread.UncaughtExceptionHandleruncaughtException方法: public void uncaughtException(Thread t, Throwable e)(2) uncaughtException方法会捕获线程的异常,此时需要覆写该方法设定自定义的处理方式。(3) 设置UncaughtExceptionHandler异常处理:方式一:通过Thread提供的静态static方法,设置默认异常处理:public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler ux)方式二:通过方法:public void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)(4) UncaughtExceptionHandler异常处理需要设置在run()方法内,否则无法捕获到线程的异常。本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-12/138947.htm