Java线程池中execute()和submit()的区别全解析(源码&实战)

 更新时间:2026年02月07日 11:45:00   作者:Knight_AL  
这篇文章主要介绍了Java线程池中execute()和submit()区别的相关资料,它们之间的主要区别在于submit方法可以返回结果、捕获异常、支持任务取消和批量汇总结果,而execute方法则不关心返回值,异常会直接抛出,需要的朋友可以参考下

前言

在 Java 并发编程里, ThreadPoolExecutor 是最常用的组件之一,而其中最常用的两个方法就是:

execute(Runnable command)
submit(Callable/Runnable task)

看起来只有“是否有返回值”的差别?

其实远不止如此!

一、简单对比:一张表记住核心差异

项目execute()submit()
所属接口ExecutorExecutorService
接受参数RunnableRunnable / Callable
是否有返回值❌ 无✔ Future,可取消,可拿结果
异常处理❗异常直接抛出到线程的 UncaughtExceptionHandler🔒 异常被捕获放进 Future(不会直接打印)
是否可取消❌ 无✔ 可用 Future.cancel()
是否支持批量汇总结果❌ 不支持✔ 支持 Future + CompletionService

一句话总结:

execute 用来“执行任务”, submit 用来“管理任务”。

二、execute():轻量级任务执行,不关心结果

executor.execute(() -> {
    System.out.println("logging...");
    int x = 1 / 0;  // 会打印异常栈
});

特点:

  • 不关心返回值
  • 异常会直接抛到控制台
  • 性能开销更小(不创建 FutureTask)

适用场景:

  • 记录访问日志
  • 异步发 MQ、埋点
  • 刷缓存、通知等“扔过去就不管了”的任务

三、submit():带状态的任务管理,有返回值,可捕获异常

Future<Integer> future = executor.submit(() -> {
    return 123;
});
System.out.println(future.get()); // 结果 123

submit 最大的隐形区别:异常不会自动抛出

Future<?> f = executor.submit(() -> {
    throw new RuntimeException("error");
});

f.get(); // ExecutionException:异常从这里抛出

为什么?

因为 submit 内部把任务包成了 FutureTask,它会:

try {
    call()
} catch (Throwable t) {
    setException(t);  // 保存到 Future
}

→ 所以异常不会直接爆出来,而是等你 future.get() 再抛。

四、源码视角:submit 底层其实也是调用 execute

submit 并不是独立执行任务,它是:

  1. 把 Runnable/Callable 包装成 FutureTask
  2. 调用 execute 执行 FutureTask

源码(摘自 AbstractExecutorService):

public <T> Future<T> submit(Callable<T> task) {
    RunnableFuture<T> f = newTaskFor(task);
    execute(f);  // 注意这里!
    return f;
}

而 execute 是线程池真正调度任务的入口。

五、异常处理的根本差别(重点!)

方法任务内部抛异常会怎样?
execute异常会冒泡到线程顶层 → 默认打印栈追踪
submit异常被 FutureTask 捕获 → 不会打印,需要 future.get() 才能感知到

示例:submit 吃掉异常

executor.submit(() -> {
    throw new RuntimeException("Boom!");
});

// 控制台不会输出任何异常

如果你不 get(),异常就彻底静悄悄消失了,这在真实项目里非常危险。

“为什么 submit() 会吃掉异常?怎么处理?”

答案:用 get() 捕获 ExecutionException,从 cause 拿真正异常。

六、真实业务场景如何选择?

✔ execute() 适用于:

  • 不需要返回值
  • 不需要任务取消
  • 不关心任务是否失败

典型业务:

  • 访问日志
  • 埋点
  • 异步通知
  • 缓存刷新

✔ submit() 适用于:

  • 需要汇总结果(并发调用多个服务)
  • 需要捕获异常
  • 需要任务状态(是否完成、是否失败)
  • 需要 cancel

典型业务(例如医疗系统):

  • 药审 + 过敏 + 医保试算:并发执行,返回综合结果
  • 大报表导出:后台执行 + 查询状态 + 可取消
  • 风险评估:多线程计算指标后统一合并
  • 第三方接口调用:需要捕获异常、重试、降级

七、一个真实示例:医疗系统并发校验医嘱

Future<DrugAuditResult> drugF = pool.submit(() -> drugAudit());
Future<AllergyResult> allergyF = pool.submit(() -> checkAllergy());
Future<InsuranceResult> insF = pool.submit(() -> preCalcInsurance());

try {
    DrugAuditResult d = drugF.get();
    AllergyResult a = allergyF.get();
    InsuranceResult i = insF.get();
    return new Summary(d, a, i);
} catch (ExecutionException e) {
    log.error("校验失败", e.getCause());
    throw new BusinessException("医嘱校验失败");
}

这里必须用 submit,因为你要:

  • 拿返回值
  • 捕获异常
  • 汇总结果

八、最终总结

execute 和 submit 的本质区别:

关键点executesubmit
是否包装 Future?❌ 否✔ 是
异常如何处理?直接抛出存 Future 内,get 时抛
是否有返回值?
是否可取消?
是否适合任务编排/汇总结果?

execute 用来“执行任务”, submit 用来“管理任务”。

到此这篇关于Java线程池中execute()和submit()区别的文章就介绍到这了,更多相关Java线程池execute()和submit()内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JavaWeb会话技术详解与案例

    JavaWeb会话技术详解与案例

    会话技术:在Web开发中,服务器跟踪用户信息的奇数称为会话技术。会话:指的是一个客户端与服务器发生的一系列请求和响应的过程。由于请求包含的信息,在请求被销毁后也就不存在,多次让用户输入账号密码,会影响用户的使用体验感,基于此,产生了cookie和session技术
    2021-11-11
  • arthas jprofiler做复杂链路的调用分析

    arthas jprofiler做复杂链路的调用分析

    这篇文章主要为大家介绍了arthas jprofiler做复杂链路的调用分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Java语言获取TCP流的实现步骤

    Java语言获取TCP流的实现步骤

    使用Wireshark分析网络包时,一个很常用的功能就是选中一个TCP报文,然后查看这个TCP报文的TCP流,从而可以进一步分析建连是否慢了,断连是否正常等情况,那么本文就TCP流的概念以及在Java中如何获取,做一个简单的学习,需要的朋友可以参考下
    2023-11-11
  • Java多线程中的ThreadLocal应用场景及问题解读

    Java多线程中的ThreadLocal应用场景及问题解读

    这篇文章主要介绍了Java多线程中的ThreadLocal应用场景及问题解读,ThreadLocal这个类在多线程并发中主要的使用场景是什么呢,我们都知道多线程并发问题实际就是多个线程对公共资源访问和修改问题,需要的朋友可以参考下
    2023-12-12
  • java中Servlet Cookie取不到值原因解决办法

    java中Servlet Cookie取不到值原因解决办法

    这篇文章主要介绍了java中Servlet Cookie取不到值原因解决办法的相关资料,需要的朋友可以参考下
    2017-06-06
  • idea打包不出现target的原因及解决

    idea打包不出现target的原因及解决

    文章主要介绍了在使用Maven进行项目打包时,`packaging` 属性的重要性和配置方法,默认情况下,Maven会将项目打包成jar包,如果项目是父级项目,则`packaging`属性应设置为`pom`,并通过`modules`标签引入子项目,这样可以确保项目的模块化管理和正确的构建顺序
    2024-11-11
  • java中BigDecimal里面的subtract函数介绍及实现方法

    java中BigDecimal里面的subtract函数介绍及实现方法

    在Java中实现减法操作需要根据数据类型选择不同方法,主要分为数值型减法和字符串减法两种场景,本文给大家介绍java中BigDecimal里面的subtract函数及实现方法,感兴趣的朋友一起看看吧
    2025-06-06
  • Spring中的retry重试组件详解

    Spring中的retry重试组件详解

    这篇文章主要介绍了Spring中的retry重试组件详解,Retry重试组件是一个处理重试逻辑的工具,可以在出现异常或失败情况下自动进行重试操作,从而提高程序的稳定性和可靠性,需要的朋友可以参考下
    2023-10-10
  • Java Scala之模式匹配与隐式转换

    Java Scala之模式匹配与隐式转换

    在Java中我们有switch case default这三个组成的基础语法,在Scala中我们是有match和case组成 default的作用由case代替,本文详细介绍了Scala的模式匹配与隐式转换,感兴趣的可以参考本文
    2023-04-04
  • SpringBoot配置Https入门实践

    SpringBoot配置Https入门实践

    本文主要介绍了SpringBoot配置Https入门实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-11-11

最新评论