多线程异常处理
子线程异常不能抛给主线程处理
public static void main(String[] args) {
try {
Thread thread = new Thread(() -> {
int a = 1 / 0;
});
thread.start();
} catch (Exception t) {
System.out.println("thread exception is caughted here!");
}
}
运行结果:
可以看出子线程的异常,主线程不能捕获。那么怎么处理多线程的异常呢?
方法一:设置线程的uncaughtExceptionHandler属性
因为多线程的抛出的未捕获异常会抛给JVM处理,JVM会调用线程的dispatchUncaughtException方法处理异常
private void dispatchUncaughtException(Throwable e) {
getUncaughtExceptionHandler().uncaughtException(this, e);
}
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler != null ?
uncaughtExceptionHandler : group;
}
如果线程设置了uncaughtExceptionHandler属性则通过其处理,如果没有设置则交给其所在线程组的uncaughtExceptionHandler处理
方法二:重写线程所在ThreadGroup的uncaughtExceptionHandler
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
parent.uncaughtException(t, e);
} else {
Thread.UncaughtExceptionHandler ueh =
Thread.getDefaultUncaughtExceptionHandler();
if (ueh != null) {
ueh.uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) {
System.err.print("Exception in thread \""
+ t.getName() + "\" ");
e.printStackTrace(System.err);
}
}
}
如果当前线程组未重写uncaughtException方法,则会向上寻找它的父ThreadGroup,直到找到一个重写了uncaughtException方法的parent,否则就默认将异常打印出来。
小结:多线程处理异常机制:抛出未捕获异常 —》 JVM捕获 —》 交给当前线程的uncaughtExceptionHandler处理 —》交给其所在ThreadGroup处理—》交给Thread的DefaultUncaughtExceptionHandler处理—》打印在控制台
但是我们多线程通常是交给线程池处理,那么线程池里线程出现异常应该如何处理呢?
线程池的excute
首先通过前面的方法设置是不行的,因为excute实际会通过线程工程创建一个新的线程,去执行新线程的run方法,新线程的run方法里面包含了传过来线程的run方法
public void run() {
runWorker(this);
}
protected void afterExecute(Runnable r, Throwable t) { }
excute的异常处理机制是:交给afterExecute()处理,默认afterExecute()是未实现的,所以excute的异常处理可以通过下面的方式实现
方法一: 自定义一个继承ThreadPoolExecutor的类,自己实现afterExecute方法,对异常进行统一处理
方法二: 可以在线程运行时通过Thread.currentThread().setUncaughtExceptionHandler设置当前线程的异常处理
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.execute(new Runnable() {
@Override
public void run() {
Thread.currentThread().setUncaughtExceptionHandler((thread, exception) -> {
System.out.println("deal exception");
});
int a = 1 / 0;
}
});
线程池的submit
submit方法会创建一个FurtureTask对象,需要通过FutureTask对象调用get方法获取结果或者异常,因为运行的结果或者异常都会赋值变量outcome,需要通过get来获取。
版权声明:本文为a282608054原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。