Java 线程池 execute() 和 submit() 对比

execute() 和 submit() 都是线程池提交任务 的核心方法,都属于 ExecutorService 线程池接口,核心区别 :execute() 无返回值、不处理异常;submit() 有返回值、会捕获异常。

下面从核心定义、使用场景、返回值、异常处理、方法归属等维度做清晰对比,附实战代码。


一、核心区别速查表

对比项 execute() submit()
返回值 void,无返回结果 Future<T>,可获取任务执行结果/状态
异常处理 直接抛出异常(会终止线程,从线程池移除) 自动捕获异常,需通过 Future.get() 才抛出
任务类型 只能提交 Runnable 无返回值任务 可提交 Runnable + Callable 有返回值任务
使用场景 执行不需要结果、不关心异常的异步任务 执行需要结果、需要捕获异常的异步任务
方法归属 定义在 Executor 顶层接口 定义在 ExecutorService 子接口
源码设计 最基础的任务提交方法 基于 execute() 封装,功能更强

二、详细解析

1. 返回值区别(最核心)

  • execute() :void,提交后无法跟踪任务是否执行完成、无法获取结果。
  • submit() :返回 Future 对象,可通过它:
    • 判断任务是否完成
    • 取消任务
    • 获取任务执行结果
    • 获取任务抛出的异常

2. 异常处理区别(关键坑点)

  • execute() :任务抛出未捕获异常 时,直接打印堆栈、终止线程,线程会从线程池被移除。
  • submit() :无论任务抛什么异常,都不会直接抛出 ,异常会被存起来,只有调用 Future.get() 时才会抛出。

3. 支持的任务类型区别

  • execute() :仅支持 Runnable(无返回值)。
  • submit() :支持两种任务:
    1. Runnable(无返回值)
    2. Callable<T>(有返回值,能抛异常)

三、实战代码示例

1. execute() 使用

java 复制代码
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecuteDemo {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newSingleThreadExecutor();
        
        // 提交无返回值任务
        pool.execute(() -> {
            System.out.println("execute 执行任务");
            // 异常会直接抛出,导致线程死亡
            // int i = 1 / 0;
        });
        
        pool.shutdown();
    }
}

✅ 适用:日志打印、消息发送、异步更新缓存等不需要结果、不关心异常的任务。


2. submit() 使用(获取返回值)

java 复制代码
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class SubmitDemo {
    public static void main(String[] args) throws Exception {
        ExecutorService pool = Executors.newSingleThreadExecutor();

        // 提交 Callable 任务,有返回值
        Future<Integer> future = pool.submit(new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                System.out.println("submit 执行任务");
                return 1 + 1; // 返回结果
            }
        });

        // 获取任务结果(阻塞等待)
        Integer result = future.get();
        System.out.println("任务结果:" + result); // 输出 2

        pool.shutdown();
    }
}

✅ 适用:异步计算、接口并行调用、需要获取执行结果/处理异常的任务。


3. submit() 异常处理演示

java 复制代码
Future<Integer> future = pool.submit(() -> {
    System.out.println("submit 任务");
    int i = 1 / 0; // 抛异常
    return 100;
});

// 异常不会直接抛出!
// 只有调用 get() 才会抛出 ExecutionException
try {
    future.get();
} catch (Exception e) {
    System.out.println("捕获到异常:" + e.getCause());
}

四、底层原理(简单理解)

submit() 本质是对 execute() 的封装:

  1. 把任务包装成 FutureTask(同时实现 Runnable + Future)
  2. 调用 execute() 提交
  3. 执行结果/异常存入 FutureTask,通过 get() 获取

五、如何选择?

  1. 只用 execute() :
    任务不需要返回值 、异常自己处理(try-catch)、不关心执行状态。
  2. 必须用 submit() :
    • 需要获取任务结果
    • 需要判断任务是否完成/取消任务
    • 需要统一捕获任务异常
    • 提交 Callable 带返回值的任务

总结

  1. execute():轻量、无返回、异常直接抛 → 适合简单异步执行。
  2. submit():强大、有返回、可捕获异常 → 适合需要结果/管控的任务。
  3. 日常开发:简单任务用 execute,复杂任务用 submit + Future。
相关推荐
silvamux_几秒前
10款模型写种草笔记:可发布性、返工来源与成本数据缺口复盘
java·数据库·笔记
bkspiderx36 分钟前
基于Socket的广播通信及C语言实现详解
c语言·开发语言·socket·广播·socket的广播通信
小王C语言40 分钟前
Qt常用控件:输入类控件,单行/多行输入框、下拉框、(日期)微调框、旋钮、滑动条
开发语言·qt
ESDWAN44 分钟前
SD-WAN 主备切换为什么仍然会断网?从检测机制到会话恢复分析
开发语言·php
步行cgn1 小时前
StringHttpMessageConverter 详解:Spring MVC 中字符串读写的默认转换器
java·spring·mvc
摇滚侠1 小时前
《On Java 中文版 基础卷》阅读笔记 实现隐藏 11
java·笔记·python
1001101_QIA1 小时前
.exe does not seem to be a Qt executable.
开发语言·qt
小蒜学长1 小时前
基于Spring Boot+Vue3的在线医疗咨询系统的设计与实现(代码+数据库+LW)
java·spring boot·后端·在线问诊·在线医疗咨询系统
Deng桑1 小时前
SpringAI写第一个Agent-把工单循环跑起来
java·agent·工具调用·spring ai
echome8881 小时前
Python 异常处理:try、else、finally 的正确搭配
开发语言·前端·python·异常处理·编程技巧