在使用java.util.concurrent下關於線程池一些類的時候,相信很多人和我一樣,總是分不清submit()和execute()的區別,今天從源碼方面分析總結一下。
通常,我們通過Executors這個工具類提供多種方法來創建適合不同場景的線程池,這里就不一一介紹了。
例如,創建可緩存線程池,Executors.newCachedThreadPool(),源碼如下:
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
通過上面源碼可以看出,該方法返回的是一個ExecutorService接口,而這個接口繼承Executor接口,Executor是最上層的,其中只包含一個execute()
方法:
public interface Executor { void execute(Runnable command); }
execute()方法的入參為一個Runnable,返回值為void,這時候我們已經知道了execute()方法的來源以及其定義。
接下來,我們來看看,submit()是從哪來的呢?
通過猜測,應該是ExecutorService接口中的,果然,打開源碼,看到了submit()方法:
public interface ExecutorService extends Executor {
... <T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result); Future<?> submit(Runnable task);
... }
可以看出,在ExecutorService接口中,一共有以上三個sumbit()方法,入參可以為Callable<T>,也可以為Runnable,而且方法有返回值Future<T>;
(補充說明:Callable<T>與Runnable類似,也是創建線程的一種方式,實現其call()方法即可,方法可以有返回值,而且方法上可以拋出異常;)
總結,從上面的源碼以及講解可以總結execute()和submit()方法的區別:
1. 接收的參數不一樣;
2. submit()有返回值,而execute()沒有;
例如,有個validation的task,希望該task執行完后告訴我它的執行結果,是成功還是失敗,然后繼續下面的操作。
3. submit()可以進行Exception處理;
例如,如果task里會拋出checked或者unchecked exception,而你又希望外面的調用者能夠感知這些exception並做出及時的處理,那么就需要用到submit,通過對Future.get()進行拋出異常的捕獲,然后對其進行處理。