Java線程池的execute和submit方法的區別(轉)
原文:https://zhuanlan.zhihu.com/p/1894001201957278410
作者:軟件求生
來源:知乎
來自社招面試的靈魂拷問
時間回到去年這個時候,我還在準備從原公司跳槽的社招,面了一家國內TOP 10的互聯網公司(名字保密哈~)。
面試官突然問我:
“你知道線程池中 submit() 和 execute() 的區別嗎?”
我嘴角一笑,心想:“這不是基礎題嗎?”
“submit 可以拿返回值,execute 不可以!”我自信作答。
面試官點點頭,然后輕描淡寫地說了一句:
“你說得沒錯,那你能說說它們底層是怎么實現的嗎?還有,它們對異常的處理方式一樣嗎?”
我:???
基礎回答,90%的候選人都停在這里
如果你在面試中遇到這個問題,大多數人(包括我當初)都會這樣答:
- execute() 是 Executor 接口中定義的方法,只能執行 Runnable 任務,沒有返回值;
- submit() 是 ExecutorService 接口新增的方法,可以執行 Runnable 或 Callable 任務,并返回一個 Future 對象。
沒錯,這個回答正確。
但也僅限于“正確”,離“驚艷”還有點距離。
如果你能再補充下面這些點,那才叫“把握住了整場面試的節奏”。
面試官真正想聽的,是這幾個“深水區”問題
我們逐個拆解一下,submit() 和 execute() 真正的區別在哪。
1. 本質區別:返回值 vs 無返回值?
我們先從最直觀的感受說起:

- submit() 會返回一個 Future 對象,允許你通過 future.get() 獲取任務執行結果。
- 而 execute() 是個“啞巴”——它負責“干活”,但從不“反饋”。
這意味著:
- submit() 更適合需要獲取返回值、檢測執行結果、處理異常的任務;
- execute() 更適合只管執行,不關心結果的 fire-and-forget 場景。
這部分很多文章都有講,我們不多說。
接下來進入真正的“深水區”:
2. 異常處理行為大不同(這點90%的人沒搞清)
先來看一段代碼:

問題:這兩段代碼執行后,控制臺會打印異常棧嗎?
答案是:
- execute() 提交的任務,如果拋出未捕獲異常,會在控制臺打印堆棧信息。
- submit() 提交的任務,即使拋出異常,也不會在控制臺打印任何東西!
為什么?因為 submit() 的任務是被封裝進了 FutureTask 中,異常也“吞”進去了,只有你主動調用 future.get() 才會拋出異常。

這就意味著:
- submit() 很“安靜”,但異常可能悄悄把你的線程搞掛了,還不告訴你;
- execute() 很“直接”,出事了就爆出來,調試起來反而容易。
面試高階回答點:
- submit() 會吞掉異常,除非主動通過 Future.get() 觸發,否則可能導致異常“沉默”;這在業務代碼中是個常見“坑”。
一起追源碼,看清“內幕”
execute() 源碼實現

這是 Executor 接口的方法,ExecutorService 繼承了它,直接使用。
submit() 源碼實現(以 Runnable 為例)

你看出來了嗎?
- submit() 的本質,其實也是調用了 execute(),不過是把任務封裝成了 FutureTask 再執行!
- 也就是說,submit() 是 execute() 的一個增強版,提供了任務跟蹤能力(Future)、異常封裝、返回值機制。
真實開發中如何選擇?
我們來看幾個業務場景:
場景一:任務只做一些異步日志記錄、埋點上傳,失敗了也無所謂
- 用 execute() 最合適,簡單直接,高性能,無需關心結果。
場景二:你需要知道任務是否執行成功
- 用 submit(),然后通過 Future.get() 獲取返回值或者異常。
比如:

場景三:批量提交多個任務,并等待所有結果
- 用 submit(),然后通過 invokeAll() 批量獲取 Future 列表,統一處理。
面試進階回答模版(建議收藏)
如果你要答這個題,推薦這樣的結構:
“execute() 是 Executor 接口定義的,不能獲取返回值;
submit() 是 ExecutorService 擴展的,適合處理需要返回結果的任務。
它本質是將任務封裝成 FutureTask,然后調用 execute() 實現執行。
兩者最大的區別在于異常處理:
execute() 拋出的異常會直接打印;submit() 會被 FutureTask 吞掉,只有在 get() 時才暴露出來。
所以在業務開發中,如果不調用 get(),可能會造成異常丟失,導致 bug 難以定位。”
如果你能再加上一段源碼分析,那就完美了!
小米的踩坑回憶錄:我曾經被 submit 的異常“坑慘了”
在我剛入職第二家公司時,有次寫了一個批量推送任務,使用線程池的 submit() 提交。
上線后一切正常,結果過了幾天突然被客戶投訴推送異常了。
查看日志,壓根沒發現任何異常信息,debug 也沒看出來問題。
后來才發現,我的 submit() 后根本沒調用 get(),導致里面拋的異常全被吞了!
于是我痛定思痛,寫了一套線程池封裝工具類,凡是 submit 的任務,都會自動監聽 Future 的狀態,并在失敗時記錄日志。順帶,還寫了一篇技術博客(哈哈~就是這篇的“前身”)。
總結一下,方便收藏復習

最后的的最后:面試中別忘了這些!
- submit() 的異常處理千萬別忘了!一定要 future.get()。
- 說區別時,不要只說“一個有返回值一個沒有”,那太基礎。
- 最好結合業務場景說“什么時候選哪個”,讓面試官覺得你是能落地的人。
- 源碼分析一定加分,不要怕說錯,大膽講邏輯。
END
好了,今天的分享就到這里啦~
如果你覺得這篇文章對你有幫助,歡迎點個【贊】【在看】或者【分享給小伙伴】,我會繼續更新更多“面試真題 + 實戰經驗 + 技術故事”的內容!
我們下次見~
我是小米,一個喜歡分享技術的31歲程序員。如果你喜歡我的文章,歡迎關注我的微信公眾號“軟件求生”,獲取更多技術干貨!
http://weixin.qq.com/r/MxywqEPElh7prQfL90kh (二維碼自動識別)

浙公網安備 33010602011771號