Java線程池中execute()和submit()的區(qū)別全解析(源碼&實(shí)戰(zhàn))
前言
在 Java 并發(fā)編程里, ThreadPoolExecutor 是最常用的組件之一,而其中最常用的兩個(gè)方法就是:
execute(Runnable command)
submit(Callable/Runnable task)
看起來(lái)只有“是否有返回值”的差別?
其實(shí)遠(yuǎn)不止如此!
一、簡(jiǎn)單對(duì)比:一張表記住核心差異
| 項(xiàng)目 | execute() | submit() |
|---|---|---|
| 所屬接口 | Executor | ExecutorService |
| 接受參數(shù) | Runnable | Runnable / Callable |
| 是否有返回值 | ? 無(wú) | ? Future,可取消,可拿結(jié)果 |
| 異常處理 | ?異常直接拋出到線程的 UncaughtExceptionHandler | ?? 異常被捕獲放進(jìn) Future(不會(huì)直接打?。?/td> |
| 是否可取消 | ? 無(wú) | ? 可用 Future.cancel() |
| 是否支持批量匯總結(jié)果 | ? 不支持 | ? 支持 Future + CompletionService |
一句話總結(jié):
execute 用來(lái)“執(zhí)行任務(wù)”, submit 用來(lái)“管理任務(wù)”。
二、execute():輕量級(jí)任務(wù)執(zhí)行,不關(guān)心結(jié)果
executor.execute(() -> {
System.out.println("logging...");
int x = 1 / 0; // 會(huì)打印異常棧
});

特點(diǎn):
- 不關(guān)心返回值
- 異常會(huì)直接拋到控制臺(tái)
- 性能開(kāi)銷(xiāo)更?。ú粍?chuàng)建 FutureTask)
適用場(chǎng)景:
- 記錄訪問(wèn)日志
- 異步發(fā) MQ、埋點(diǎn)
- 刷緩存、通知等“扔過(guò)去就不管了”的任務(wù)
三、submit():帶狀態(tài)的任務(wù)管理,有返回值,可捕獲異常
Future<Integer> future = executor.submit(() -> {
return 123;
});
System.out.println(future.get()); // 結(jié)果 123

submit 最大的隱形區(qū)別:異常不會(huì)自動(dòng)拋出
Future<?> f = executor.submit(() -> {
throw new RuntimeException("error");
});
f.get(); // ExecutionException:異常從這里拋出

為什么?
因?yàn)?submit 內(nèi)部把任務(wù)包成了 FutureTask,它會(huì):
try {
call()
} catch (Throwable t) {
setException(t); // 保存到 Future
}
→ 所以異常不會(huì)直接爆出來(lái),而是等你 future.get() 再拋。
四、源碼視角:submit 底層其實(shí)也是調(diào)用 execute
submit 并不是獨(dú)立執(zhí)行任務(wù),它是:
- 把 Runnable/Callable 包裝成 FutureTask
- 調(diào)用 execute 執(zhí)行 FutureTask
源碼(摘自 AbstractExecutorService):
public <T> Future<T> submit(Callable<T> task) {
RunnableFuture<T> f = newTaskFor(task);
execute(f); // 注意這里!
return f;
}
而 execute 是線程池真正調(diào)度任務(wù)的入口。
五、異常處理的根本差別(重點(diǎn)?。?/h2>
| 方法 | 任務(wù)內(nèi)部拋異常會(huì)怎樣? |
|---|---|
| execute | 異常會(huì)冒泡到線程頂層 → 默認(rèn)打印棧追蹤 |
| submit | 異常被 FutureTask 捕獲 → 不會(huì)打印,需要 future.get() 才能感知到 |
示例:submit 吃掉異常
executor.submit(() -> {
throw new RuntimeException("Boom!");
});
// 控制臺(tái)不會(huì)輸出任何異常
如果你不 get(),異常就徹底靜悄悄消失了,這在真實(shí)項(xiàng)目里非常危險(xiǎn)。
“為什么 submit() 會(huì)吃掉異常?怎么處理?”
答案:用 get() 捕獲 ExecutionException,從 cause 拿真正異常。
六、真實(shí)業(yè)務(wù)場(chǎng)景如何選擇?
? execute() 適用于:
- 不需要返回值
- 不需要任務(wù)取消
- 不關(guān)心任務(wù)是否失敗
典型業(yè)務(wù):
- 訪問(wèn)日志
- 埋點(diǎn)
- 異步通知
- 緩存刷新
? submit() 適用于:
- 需要匯總結(jié)果(并發(fā)調(diào)用多個(gè)服務(wù))
- 需要捕獲異常
- 需要任務(wù)狀態(tài)(是否完成、是否失?。?/li>
- 需要 cancel
典型業(yè)務(wù)(例如醫(yī)療系統(tǒng)):
- 藥審 + 過(guò)敏 + 醫(yī)保試算:并發(fā)執(zhí)行,返回綜合結(jié)果
- 大報(bào)表導(dǎo)出:后臺(tái)執(zhí)行 + 查詢狀態(tài) + 可取消
- 風(fēng)險(xiǎn)評(píng)估:多線程計(jì)算指標(biāo)后統(tǒng)一合并
- 第三方接口調(diào)用:需要捕獲異常、重試、降級(jí)
七、一個(gè)真實(shí)示例:醫(yī)療系統(tǒng)并發(fā)校驗(yàn)醫(yī)囑
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("校驗(yàn)失敗", e.getCause());
throw new BusinessException("醫(yī)囑校驗(yàn)失敗");
}
這里必須用 submit,因?yàn)槟阋?/p>
- 拿返回值
- 捕獲異常
- 匯總結(jié)果
八、最終總結(jié)
execute 和 submit 的本質(zhì)區(qū)別:
| 關(guān)鍵點(diǎn) | execute | submit |
|---|---|---|
| 是否包裝 Future? | ? 否 | ? 是 |
| 異常如何處理? | 直接拋出 | 存 Future 內(nèi),get 時(shí)拋 |
| 是否有返回值? | 無(wú) | 有 |
| 是否可取消? | 否 | 是 |
| 是否適合任務(wù)編排/匯總結(jié)果? | ? | ? |
execute 用來(lái)“執(zhí)行任務(wù)”, submit 用來(lái)“管理任務(wù)”。
到此這篇關(guān)于Java線程池中execute()和submit()區(qū)別的文章就介紹到這了,更多相關(guān)Java線程池execute()和submit()內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
arthas?jprofiler做復(fù)雜鏈路的調(diào)用分析
這篇文章主要為大家介紹了arthas?jprofiler做復(fù)雜鏈路的調(diào)用分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
Java語(yǔ)言獲取TCP流的實(shí)現(xiàn)步驟
使用Wireshark分析網(wǎng)絡(luò)包時(shí),一個(gè)很常用的功能就是選中一個(gè)TCP報(bào)文,然后查看這個(gè)TCP報(bào)文的TCP流,從而可以進(jìn)一步分析建連是否慢了,斷連是否正常等情況,那么本文就TCP流的概念以及在Java中如何獲取,做一個(gè)簡(jiǎn)單的學(xué)習(xí),需要的朋友可以參考下2023-11-11
Java多線程中的ThreadLocal應(yīng)用場(chǎng)景及問(wèn)題解讀
這篇文章主要介紹了Java多線程中的ThreadLocal應(yīng)用場(chǎng)景及問(wèn)題解讀,ThreadLocal這個(gè)類(lèi)在多線程并發(fā)中主要的使用場(chǎng)景是什么呢,我們都知道多線程并發(fā)問(wèn)題實(shí)際就是多個(gè)線程對(duì)公共資源訪問(wèn)和修改問(wèn)題,需要的朋友可以參考下2023-12-12
java中BigDecimal里面的subtract函數(shù)介紹及實(shí)現(xiàn)方法
在Java中實(shí)現(xiàn)減法操作需要根據(jù)數(shù)據(jù)類(lèi)型選擇不同方法,主要分為數(shù)值型減法和字符串減法兩種場(chǎng)景,本文給大家介紹java中BigDecimal里面的subtract函數(shù)及實(shí)現(xiàn)方法,感興趣的朋友一起看看吧2025-06-06
SpringBoot配置Https入門(mén)實(shí)踐
本文主要介紹了SpringBoot配置Https入門(mén)實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-11-11

