在 Java 线程池中,submit()
和 execute()
是提交任务的两种核心方法,它们在功能和使用上有显著区别。
下面从多个维度进行详细分析:
特性 | execute() | submit() |
---|---|---|
返回值 | 无 (void ) | 返回 Future 对象 |
支持的任务类型 | 仅 Runnable | Runnable 和 Callable |
异常处理 | 直接抛出到未捕获异常处理器 | 异常封装在 Future 中 |
结果获取 | 无法获取任务结果 | 可通过 Future.get() 获取结果或异常 |
方法来源 | Executor 接口定义 | ExecutorService 接口扩展 |
任务取消 | 不支持 | 可通过 Future.cancel() 取消任务 |
适用场景:不需要结果、不关心异常的后台任务
ExecutorService executor = Executors.newFixedThreadPool(3);
// 提交 Runnable 任务(无返回值)
executor.execute(() -> {
System.out.println("任务开始执行...");
// 模拟业务逻辑
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// 异常直接抛出到未捕获异常处理器
Thread.currentThread().interrupt();
}
System.out.println("任务执行完成");
});
executor.shutdown();
适用场景:需要结果、异常处理、任务取消等复杂场景
ExecutorService executor = Executors.newFixedThreadPool(3);
// 场景1:提交 Runnable 任务(可获取执行状态)
Future<?> future1 = executor.submit(() -> {
System.out.println("Runnable 任务执行中");
// 任务代码...
});
// 场景2:提交 Callable 任务(获取返回值)
Future<Integer> future2 = executor.submit(() -> {
System.out.println("Callable 任务计算中");
// 模拟计算
return 42; // 返回计算结果
});
// 场景3:带结果的 Runnable
Future<String> future3 = executor.submit(() -> {
System.out.println("带结果的 Runnable");
// 执行操作但不返回值
}, "操作成功"); // 预定义结果
// 获取任务结果
try {
System.out.println("Future1 状态: " + future1.get()); // 输出 null
System.out.println("Future2 结果: " + future2.get()); // 输出 42
System.out.println("Future3 结果: " + future3.get()); // 输出 "操作成功"
} catch (ExecutionException e) {
System.err.println("任务执行异常: " + e.getCause());
} finally {
executor.shutdown();
}
executor.execute(() -> {
try {
// 业务代码...
} catch (Exception e) {
// 必须显式处理异常
System.err.println("捕获异常: " + e);
}
throw new RuntimeException("未处理异常"); // 会被传递到未捕获异常处理器
});
// 设置全局异常处理器
Thread.setDefaultUncaughtExceptionHandler((thread, ex) -> {
System.err.println("线程 " + thread.getName() + " 抛出异常: " + ex);
});
Future<?> future = executor.submit(() -> {
throw new IllegalStateException("测试异常");
});
try {
future.get(); // 在此处捕获异常
} catch (ExecutionException e) {
Throwable cause = e.getCause();
System.err.println("捕获提交任务的异常: " + cause.getClass() + ": " + cause.getMessage());
// 输出:捕获提交任务的异常: class java.lang.IllegalStateException: 测试异常
}
Future<String> future = executor.submit(() -> {
Thread.sleep(5000); // 模拟长任务
return "结果";
});
try {
// 设置2秒超时
String result = future.get(2, TimeUnit.SECONDS);
System.out.println("结果: " + result);
} catch (TimeoutException e) {
System.err.println("任务超时,尝试取消");
future.cancel(true); // 中断正在执行的任务
} catch (CancellationException e) {
System.err.println("任务已被取消");
}
List<Callable<Integer>> tasks = Arrays.asList(
() -> { Thread.sleep(1000); return 1; },
() -> { Thread.sleep(2000); return 2; },
() -> { Thread.sleep(500); return 3; }
);
// 提交所有任务
List<Future<Integer>> futures = executor.invokeAll(tasks);
// 处理结果
for (Future<Integer> future : futures) {
try {
System.out.println("任务结果: " + future.get());
} catch (ExecutionException e) {
System.err.println("任务失败: " + e.getCause());
}
}
graph TD
A[调用execute] --> B[线程池分配线程]
B --> C[执行Runnable.run]
C --> D{发生异常?}
D -->|是| E[传递给未捕获异常处理器]
D -->|否| F[任务结束]
graph TD
A[调用submit] --> B[包装为FutureTask]
B --> C[调用execute执行]
C --> D[执行任务代码]
D --> E{发生异常?}
E -->|是| F[保存到FutureTask]
E -->|否| G[保存结果到FutureTask]
F --> H[调用get时抛出ExecutionException]
G --> I[调用get时返回结果]
选择原则:
execute()
submit()
异常处理:
// 使用 submit() 时的推荐结构
Future<?> future = executor.submit(task);
try {
future.get(); // 显式触发异常检查
} catch (ExecutionException e) {
// 处理业务异常
handleBusinessException(e.getCause());
} catch (InterruptedException e) {
// 处理中断
Thread.currentThread().interrupt();
}
资源清理:
// 始终关闭线程池
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
性能考虑:
execute()
比 submit()
开销小约15%(基准测试数据)execute()
graph TD
A[需要提交任务] --> B{需要结果或异常控制?}
B -->|是| C[使用submit]
B -->|否| D{任务可能抛出未处理异常?}
D -->|是| E[使用submit + 全局异常处理]
D -->|否| F[使用execute]
C --> G{任务类型?}
G -->|有返回值| H[submit+Callable]
G -->|无返回值| I[submit+Runnable]
根据实际需求选择合适的方法:
execute()
submit()
+ Future
APIinvokeAll()
/invokeAny()