(一)、示例:
public class ThreadPoolDemo3 {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(4);
for (int i = 0; i < 5; i++) {
int index = i;
executorService.submit(() -> divTask(100, index));
}
executorService.shutdown();
}
private static void divTask(int a, int b) {
double result = a / b;
System.out.println(result);
}
}
运行结果:
上述代码,可以看出运行结果为4个,因该是有5个的,但是当i=0
的时候,100/0
是会报错的,但是日志信息中没有任何信息,是为什么那?如果使用了submit(Runnable task)
就会出现这种情况,任何的错误信息都出现不了!
这是因为使用submit(Runnable task) 的时候,错误的堆栈信息跑出来的时候会被内部捕获到,所以打印不出来具体的信息让我们查看,而且也没有返回值,解决的方法有如下两种:
1、使用execute()代替submit()
使用结果:
2、使用Future,实现Callable接口,它会转换成Runnable实例,并返回,这样就可以获取线程执行结果,也可能返回异常结果:
使用结果:
(二)、由于线程池在执行过程中会因为异常终止,尽管ThreadPoolExecutor会侦测这种情况,并在工作线程终止时候启动新的线程,但是由于线程创建和启动有开销,我们尽量避免未捕获的异常,可以通过setThreadFactory,为线程池关联一个线程工厂,在工厂里为每一个线程设置UncaughtExceptionHandler,不过只有执行ThreadPoolExecutor.execute调用的任务所抛出的异常才会导致UncaughtExceptionHandler调用,而调用ThreadPoolExecutor.submit不会调用UncaughtExceptionHandler。
(三)、提交给ScheduledExecutorService执行的计划任务在其执行过程中如果抛出未捕获的异常,那么该任务不会再执行,即使线程工厂为其关联一个UncaughtExceptionHandler,也不会调用。所以确保计划任务不会抛出未捕获的异常。