在Java中,线程中的异常是不能抛出到调用该线程的外部方法中捕获的。
因为线程是独立执行的代码片断,线程的问题应该由线程自己来解决,而不要委托到外部。”基于这样的设计理念,在Java中,线程方法的异常都应该在线程代码边界之内(run方法内)进行try catch并处理掉,换句话说,我们不能捕获从线程中逃逸的异常。
public static void main(String[] args){
try {
new Thread( () -> {
int i = 1/ 0;
}).start();
}catch (Exception e){
System.out.println(1);
}
}
Thread类的run()方法声明,方法声明上没有对抛出异常进行任何约束,也就是异常不会抛到外部。如果内部没有catch,那么Thread的默认异常处理就是调用 System.err 进行输出,也就是直接打印到控制台了。
public static void main(String[] args){
new Thread( () -> {
try {
int i = 1/ 0;
}catch (Exception e){
System.out.println("1");
}
}).start();
}
可以看到我们在线程内部显式的进行try/catch,异常被捕获。
查看Thread类的源码,我们可以看到有个dispatchUncaughtException方法,此方法就是用来处理线程中抛出的异常的。JVM会调用dispatchUncaughtException方法来寻找异常处理器(UncaughtExceptionHandler),处理异常。
/**
* Dispatch an uncaught exception to the handler. This method is
* intended to be called only by the JVM.
*/
private void dispatchUncaughtException(Throwable e) {
getUncaughtExceptionHandler().uncaughtException(this, e);
}
/**
* 获取用来处理未捕获异常的handler,如果没有设置则返回当前线程所属的ThreadGroup
*
**/
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler != null ?
uncaughtExceptionHandler : group;
}
uncaughtExceptionHandler
默认为null,null的话就调用线程所属group的默认handler
// 这里也就是打印到控制台
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);
}
}
}
所以我们可以通过设置Thread的uncaughtExceptionHandler
来设置异常处理器
public static void main(String[] args){
Thread thread = new Thread(() -> {
int i = 1 / 0;
});
thread.setUncaughtExceptionHandler((t, e) -> System.out.println("捕捉到异常"));
thread.start();
}
在线程池,我们可以批量的为所有线程设置uncaughtExceptionHandler
,线程是由ThreadFactory产生的,所以我们可以通过这里入手。
通过复写ThreadFactory的newThread就可实现。
public class ThreadExceptionDemo {
private static final int CORE_POOL_SIZE = 3;
private static final int MAX_POOL_SIZE = 100;
private static final int QUEUE_CAPACITY = 5;
private static final Long KEEP_ALIVE_TIME = 5L;
public static void main(String[] args){
// 在构造函数塞进去我们要的ThreadFactory
ThreadPoolExecutor executor = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(QUEUE_CAPACITY),
new MyThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy());
executor.execute(()->{
int i = 1 / 0;
});
}
}
class MyThreadFactory implements ThreadFactory{
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.out.println("捕捉到了");
}
});
return thread;
}
}
线程池的submit是带有返回值的
public static void main(String[] args){
ExecutorService executorService = Executors.newFixedThreadPool(2);
Future future = executorService.submit(()->{
int i = 1 / 0;
});
try {
future.get();
} catch (InterruptedException | ExecutionException e) {
System.out.println("捕捉到了");
}
}