如果在提交給線程池的任務(wù)中拋出了異常咆贬,這個(gè)異骋蘼可能不會(huì)打印任何內(nèi)容,也沒有被任何人捕獲智政,形成一個(gè)幽靈異常艳悔。
為了避免這種危險(xiǎn)情況的發(fā)生,有以下解決方式
- 使用Future與Callable
- 對(duì)于Runnable女仰,使用execute方法而非submit方法
以上兩種方式可以獲得異常在哪里拋出,但是仍然丟失了一個(gè)重要信息:任務(wù)的具體提交位置抡锈。
如果想進(jìn)一步獲取上述信息疾忍,需要自行擴(kuò)展ThreadPoolExecutor,使其在調(diào)度任務(wù)之前床三,先保存一下提交任務(wù)線程的堆棧信息一罩。
擴(kuò)展:
execute與submit的異同
execute是Executors的接口,submit則是ExecutorService的接口
對(duì)于ThreadPoolExecutor而言撇簿,其實(shí)現(xiàn)了execute聂渊,而sumit方法則繼承自抽象類AbstractExecutorService
對(duì)于submit方法
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask); //AbstractExecutorService未實(shí)現(xiàn)execute
return ftask;
}
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
可以看到,submit事實(shí)上封裝了一個(gè)Future四瘫。
因此汉嗽,對(duì)于Runnable而言,應(yīng)當(dāng)直接使用execute方法找蜜,無(wú)需經(jīng)由submit包裝饼暑。對(duì)于希望獲得返回值的Callable,則適合使用submit方法洗做。
參考:
Java 8 源碼
《實(shí)戰(zhàn)Java高并發(fā)程序設(shè)計(jì)》
https://blog.csdn.net/hayre/article/details/53314599