在前陣子的工作中湃窍,收到一個bug闻蛀,大概是在app運行過程中出現(xiàn)了異常,可是查看了app日志您市、系統(tǒng)日志并沒有異常日志打印觉痛。最后發(fā)現(xiàn)了context.getExternalCacheDir方法返回值為null,原以為bug可以回給系統(tǒng)組的人去修了茵休,在leader的指導下薪棒,發(fā)現(xiàn)了app中的問題:線程池啟動線程的方法為submit手蝎,而沒有對submit的返回值做處理,在運行過程中也沒有catch NPE盗尸,任務(wù)一直在線程池中錯誤循環(huán)柑船,所以導致了問題,最終將所有線程池的submit方法替換為execute方法泼各,當有未catch的execption時鞍时,會直接crash,在系統(tǒng)中打印日志扣蜻,方便后續(xù)的bug處理逆巍。
下面說說execute和submit的區(qū)別。
首先從源碼開始
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);
...
}
通過源碼莽使,submit來源于ExecutorService接口锐极,可以看出,在ExecutorService接口中芳肌,一共有以上三個sumbit()方法灵再,入?yún)⒖梢詾镃allable<T>,也可以為Runnable亿笤,而且方法有返回值Future<T>翎迁;
(補充說明:Callable<T>與Runnable類似,也是創(chuàng)建線程的一種方式净薛,實現(xiàn)其call()方法即可汪榔,方法可以有返回值,而且方法上可以拋出異常)
execute:
execute方法來源于Executor接口肃拜,上述的ExecutorService接口繼承于此痴腌,Executor是最上層的矗晃,其中只包含一個execute()方法:
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}
總結(jié):
(1)可以接受的任務(wù)類型不同
execute只能接受Runnable類型的任務(wù)
submit不管是Runnable還是Callable類型的任務(wù)都可以接受唤崭,但是Runnable返回值均為void,所以使用Future的get()獲得的還是null
(2)submit()有返回值蝗碎,而execute()沒有
例如猛蔽,有個task戚嗅,希望該task執(zhí)行完后告訴我它的執(zhí)行結(jié)果,是成功還是失敗枢舶,然后繼續(xù)下面的操作,這時需要用submit
(3)submit()可以進行Exception處理
例如替久,如果task里會拋出checked或者unchecked exception凉泄,而你又希望外面的調(diào)用者能夠感知這些exception并做出及時的處理,那么就需要用到submit蚯根,通過對Future.get()進行拋出異常的捕獲后众,然后對其進行處理胀糜。