ExecuterService submit

起因

在线上排查问题时,请求不成功,但是日志里面没有找到任何异常。

重现

写如下测试代码,发现 test1、test2 会直接抛出异常,test3 没有抛出异常,test4 在 16 行才抛出异常。

private static ExecutorService es = Executors.newSingleThreadExecutor();

public static void main(String[] args) throws InterruptedException, ExecutionException {
    // test1
    new Thread(() -> { throw new RuntimeException("in thread start");}).start();
    
    // test2
    es.execute(() -> { throw new RuntimeException("in execute");});
    
    // test3
    es.submit(() -> { throw new RuntimeException("in submit");});
    
    // test4
    Future<Object> future = es.submit(() -> { throw new RuntimeException("in submit"); });
    Thread.sleep(1000);
    future.get();
    
    es.shutdown();
}

输出如下:

原因

execute

使用 ThreadPoolExecutor.execute 执行任务时,任务原封不动提交给 Worker,若任务抛出异常,Worker 会直接再次抛出:

submit

使用 ThreadPoolExecutor.submit 执行任务时,任务会被封装成 FutureTask,FutureTask 的 run 方法会捕获异常,不会再次抛出,在 get 时才会抛出:

解决方案

方案1 - 选择 execute

若提交任务后,不需要获取返回结果,则尽量使用 execute 方法,这样就能在标准输出打印异常栈。

缺点:只能在标准输出打印异常栈,不能在日志系统里面打印,所以日志文件中还是没有异常输出。

方案2 - 从任务出发

自定义任务接口 Task,所有任务都实现 Task:

输出如下:

方案3 - 从线程池出发

自定义线程池继承 ThreadPoolExecutor,重写 afterExecute 方法:

输出如下:

Last updated

Was this helpful?