Java线程池中线程异常后:是销毁还是复用?
excute提交:

execute 提交到线程池的方式,如果执行中抛出异常,并且没有在执行逻辑中catch,那么会抛出异常,并且移除抛出异常的线程,创建新的线程放入到线程池中。


可以发现,如果抛出异常,会移除抛出异常的线程,创建新的线程。
submit提交:

submit 提交到线程池的方式,如果执行中抛出异常,并且没有catch,不会抛出异常,不会创建新的线程。
submit也是调用了execute方法,但是在调用之前,包装了一层 RunnableFuture,那一定是在RunnableFuture的实现 FutureTask中有特殊处理了,我们查看源码可以发现


但是,我们通过 java.util.concurrent.FutureTask#get(),就可以获取对应的异常信息。
总结
当一个线程池里面的线程异常后:
- 当执行方式是execute时,可以看到堆栈异常的输出,线程池会把这个线程移除掉,并创建一个新的线程放到线程池中。
- 当执行方式是submit时,堆栈异常没有输出。但是调用
Future.get()方法时,可以捕获到异常,不会把这个线程移除掉,也不会创建新的线程放入到线程池中。
附:
Runnable和Callable区别:
- 方法不同
Runnable接口只有一个run()方法,该方法不返回任何值,因此无法抛出任何checked Exception。
Callable接口则有一个call()方法,它可以返回一个值,并且可以抛出一个checked Exception。
- 返回值不同
Runnable的run()方法没有返回值,只是一个void类型的方法。
Callable的call()方法却必须有一个返回值,并且返回值的类型可以通过泛型进行指定。
- 异常处理不同
在Runnable中,我们无法对run()方法抛出的异常进行任何处理。
但在Callable中,自定义的call()方法可以抛出一个checked Exception,并由其执行者Handler进行捕获并处理。