您的位置:首页 > 编程语言 > Java开发

Java Thread线程异常监控

2017-03-03 00:00 330 查看
学习Java的同学注意了!!!
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:589809992 我们一起学Java!

一、场景描述:单线程程序可以用try...catch捕获程序的异常,而在多线程程序的时候是无法使用try...catch捕获。
示例1:多线程发生异常,无法使用try...catch捕获问题
public class NoCaughtThread  implements Runnable{
@Override public 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 {
@Override
public 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
}

@Override
public void run() {
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread arg0, Throwable e) {
// TODO Auto-generated method stub
System.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.UncaughtExceptionHandler
uncaughtException方法: 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()方法内,否则无法捕获到线程的异常。

学习Java的同学注意了!!!
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:589809992 我们一起学Java!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: