對線面試官 - 線程池
面試官:線程池有哪些執(zhí)行方法?
派大星:線程池有兩種執(zhí)行方法,分別是 execute()和 submit()。
面試官:那么 execute()和 submit()有什么區(qū)別呢?
派大星:從提交的任務(wù)類型角度來看,execute()只能提交 Runnable 類型的任務(wù),而 submit()既能提交 Runnable 類型的任務(wù),也能提交 Callable 類型的任務(wù)。此外,從 API 層面理解,execute()是在 Executor 接口中定義的,而 submit()方法是在 ExecutorService 接口中定義的,具體的實現(xiàn)是由 AbstractExecutorService 進(jìn)行。
面試官:那么 execute()和 submit()在異常處理方面有什么區(qū)別嗎?
派大星:execute()會直接拋出任務(wù)執(zhí)行時的異常,可以使用 try catch 來捕獲,和普通線程的處理方式完全一致。而 submit()會吃掉異常,可以通過 Future 的 get 方法將任務(wù)執(zhí)行時的異常重新拋出。
面試官:那么 execute()和 submit()的返回值有什么區(qū)別呢?
派大星:execute()沒有返回值,而 submit()有返回值。
面試官:從 API 層面來看,execute 方法和 submit 方法的實現(xiàn)有什么不同呢?
派大星:
execute 是在 Executor 接口中定義的。ThreadPoolExecutor()中并沒有定義,但是 ThreadPoolExecutor 類繼承了 AbstractExecutorService 抽象類,而該抽象類實現(xiàn)了 ExecutorService 接口,ExecutorService 接口又繼承了 Executor 接口??偨Y(jié):也就是說 ThreadPoolExecutor 實現(xiàn)了 execute()方法,
具體來說,AbstractExecutorService 類中 submit 方法被重載了三次,分別接受 Runnable、Callable 和 Runnable 和 ResultHandler 類型的參數(shù)。而 ThreadPoolExecutor 類中只實現(xiàn)了接受 Runnable 類型參數(shù)的 execute 方法。另外,submit 方法會返回一個 Future 對象,而 execute 方法沒有返回值。
面試官:那么如果我不需要一個結(jié)果,直接用 execute()會有什么好處嗎?
派大星:如果提交的任務(wù)不需要一個結(jié)果的話直接用 execute()會提高性能。因為 submit()底層調(diào)用的時候,又將任務(wù)交給了 execute()方法。
面試官:派大星,你能否再詳細(xì)解釋一下為什么說如果提交的任務(wù)不需要一個結(jié)果的話直接用 execute()會提高性能呢?
派大星:當(dāng)我們使用 submit()方法提交任務(wù)時,會返回一個 Future 對象,通過這個對象我們可以在任務(wù)執(zhí)行完畢后獲取執(zhí)行結(jié)果。而 execute()方法不會返回這個 Future 對象,所以如果我們提交的任務(wù)不需要一個結(jié)果,直接使用 execute()方法,就可以避免創(chuàng)建這個 Future 對象,從而提高性能。因為創(chuàng)建和管理這個 Future 對象也會帶來一定的開銷。
面試官:非常好的解釋,那如果我提交的任務(wù)需要一個結(jié)果,使用 submit()方法和 execute()方法有什么區(qū)別呢?
派大星:如果提交的任務(wù)需要一個結(jié)果,那么使用 submit()方法是比較好的選擇,因為它會返回一個 Future 對象,我們可以通過這個對象在任務(wù)執(zhí)行完畢后獲取執(zhí)行結(jié)果。而使用 execute()方法提交任務(wù)時,我們需要自己通過其他方式來獲取任務(wù)執(zhí)行結(jié)果,比如使用共享變量或者使用回調(diào)函數(shù)等方式。