前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java避坑指南:ThreadPoolExecutor提交任务出现异常,异常是否吞掉,线程是否退出的不同影响

Java避坑指南:ThreadPoolExecutor提交任务出现异常,异常是否吞掉,线程是否退出的不同影响

作者头像
崔认知
发布2023-06-19 16:53:15
1K0
发布2023-06-19 16:53:15
举报
文章被收录于专栏:nobody

前言


ThreadPoolExecutor通过execute方法提交任务,任务执行过程中出现异常,会导致线程退出,异常信息即堆栈由标准错误(System.err)输出。

ThreadPoolExecutor通过submit方法提交任务,任务执行过程中出现异常,线程不会退出,但是异常会吞掉,并且异常会设置到

java.util.concurrent.FutureTask 中返回。

源码解析:ThreadPoolExecutor通过execute方法提交任务,任务执行过程中出现异常,会导致线程退出,异常信息即堆栈由标准错误(System.err)输出


通过

代码语言:javascript
复制
java.util.concurrent.ThreadPoolExecutor#execute

方法提交任务,任务执行由:

代码语言:javascript
复制
java.util.concurrent.ThreadPoolExecutor#runWorker

执行,出现异常时会重新把异常抛出:

如果提交的任务代码没有处理异常,则有线程本身来处理:

代码语言:javascript
复制
java.lang.Thread#dispatchUncaughtException
代码语言:javascript
复制
/**
     * 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);
    }
代码语言:javascript
复制
/**
     * Returns the handler invoked when this thread abruptly terminates
     * due to an uncaught exception. If this thread has not had an
     * uncaught exception handler explicitly set then this thread's
     * {@code ThreadGroup} object is returned, unless this thread
     * has terminated, in which case {@code null} is returned.
     * @since 1.5
     * @return the uncaught exception handler for this thread
     */
    public UncaughtExceptionHandler getUncaughtExceptionHandler() {
        return uncaughtExceptionHandler != null ?
            uncaughtExceptionHandler : group;
    }

如果当前线程没有设置UncaughtExceptionHandler,则由该线程所属的线程组ThreadGroup来处理,异常信息堆栈最终由标准错误输出::

代码语言:javascript
复制
java.lang.ThreadGroup#uncaughtException

异常处理完回到任务处理流程,导致while循环从队列中取任务处理中断即线程退出,执行finally 块:

代码语言:javascript
复制
java.util.concurrent.ThreadPoolExecutor#runWorker

为即将死去的worer执行清理工作:

这种行为有什么缺陷呢?一是异常并非由日志系统输出,二是线程会退出,失去了线程池的意义。

如何避免呢?我们需要在提交的任务中自行处理异常,不再抛出此异常,并且日志输出异常堆栈,最好设置线程的UncaughtExceptionHandler 作为异常的输出兜底处理:

代码语言:javascript
复制
ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("test-pool-0")
                .setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
                    @Override
                    public void uncaughtException(Thread t, Throwable e) {
                        log.error("uncaughtException {}",t, e);
                    }
                })
                .build();

源码解析:ThreadPoolExecutor通过submit方法提交任务,任务执行过程中出现异常,线程不会退出,但是异常会吞掉,并且异常会设置到

java.util.concurrent.FutureTask 中返回


通过

代码语言:javascript
复制
java.util.concurrent.AbstractExecutorService#submit

方法提交任务,原任务被封装为

代码语言:javascript
复制
java.util.concurrent.FutureTask

以便于处理任务执行的结果。

任务执行时:

代码语言:javascript
复制
java.util.concurrent.ThreadPoolExecutor#runWorker

会执行

代码语言:javascript
复制
java.util.concurrent.FutureTask#run

当任务抛出异常时候,FutureTask 会把异常保存,不再继续抛出异常,即吞掉异常:

由于异常被吞掉,job的执行:

代码语言:javascript
复制
java.util.concurrent.ThreadPoolExecutor#runWorker

永远看不到任务的异常,while循环从队列中取任务继续执行,不会退出。

我们想要得知任务有没有异常,也只能通过:

代码语言:javascript
复制
java.util.concurrent.FutureTask#get()

获取,所以,永远不能忽略任务的结果,否则任务执行中发生的异常无从得知。

这种行为有什么缺陷呢?如果我们使用线程池的submit方法提交任务,任务没处理异常,而又不关心结果,即没调用:

代码语言:javascript
复制
java.util.concurrent.FutureTask#get()

,那我们任务的异常,就永远的丢失了。

如何避免呢?很简单,如果我们使用线程池的submit方法提交任务,一定记得调用

代码语言:javascript
复制
java.util.concurrent.FutureTask#get()

,即使我们不关心结果,也必须使用。

小结


ThreadPoolExecutor通过execute方法提交任务,任务执行过程中出现异常,会导致线程退出,异常信息即堆栈由标准错误(System.err)输出。

如何避免呢?我们需要在提交的任务中自行处理异常,不再抛出此异常,并且日志输出异常堆栈,最好设置线程的UncaughtExceptionHandler 作为异常的输出兜底处理。

ThreadPoolExecutor通过submit方法提交任务,任务执行过程中出现异常,线程不会退出,但是异常会吞掉,并且异常会设置到

java.util.concurrent.FutureTask 中返回。

如何避免呢?如果我们使用线程池的submit方法提交任务,一定记得调用

代码语言:javascript
复制
java.util.concurrent.FutureTask#get()

方法。


本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-07-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 认知科技技术团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档