java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java线程池execute()和submit()

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

作者: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;  // 会打印异常栈
});

特点:

适用场景:

三、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() 适用于:

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

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

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()内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文