Executor框架的最大優(yōu)點(diǎn)是把任務(wù)的提交和執(zhí)行解耦。要想執(zhí)行任務(wù),只需把任務(wù)描述清楚,提交即可。這個任務(wù)是怎么被執(zhí)行的,被誰執(zhí)行的,什么時候執(zhí)行的,不用關(guān)心。即,提交一個Callable對象給ExecutorService(如最常用的線程池ThreadPoolExecutor),得到一個Future對象,調(diào)用Future對象的get方法等待執(zhí)行結(jié)果。
// es管理著一個有5個線程的線程池
ExecutorService es = Executors.newFixedThreadPool(5);
//提交作業(yè)給es,任務(wù)內(nèi)容封裝在Callable中,約定好了輸出的類型是String。
String outputs = es.submit(
new Callable<String>() {
public String call() throws Exception {
return "I am a task, which submited by es, and run by those workers";
}
//提交后等待結(jié)果,到底是5個線程中哪個完成的任務(wù),不用關(guān)心
}).get();
System.out.println(outputs);
下面通過源碼來了解一下任務(wù)是如何被執(zhí)行的
接口ExecutorService繼承自Executor
他定義了完整的線程池的行為,可以接受提交任務(wù)、執(zhí)行任務(wù)、關(guān)閉服務(wù)。抽象類AbstractExecutorService類實(shí)現(xiàn)了ExecutorService接口
也實(shí)現(xiàn)了接口定義的默認(rèn)行為。
1)提交任務(wù)submit:構(gòu)造好一個FutureTask對象后,調(diào)用execute()方法執(zhí)行任務(wù)。一共有3種帶不同參數(shù)類型的submit,但最后都會返回一個FutureTask
2)執(zhí)行任務(wù)Executor:該方法在抽象類AbstractExecutorService的子類ThreadPoolExecutor中實(shí)現(xiàn)的
線程池的接收任務(wù)、維護(hù)工作線程的策略都在這個類中。
執(zhí)行execute分3步:
-
如果當(dāng)前正在工作的線程(workerCountOf)小于核心線程corePoolSize,就創(chuàng)建一個新線程(addWorker)。2. 如果任務(wù)被放入了隊(duì)列,還需要檢測是否能創(chuàng)建新線程(因?yàn)榫€程可能會在上次檢查后死亡(isRunning))或線程池是否被關(guān)閉,如果狀態(tài)不正確,需要回滾入列并停止或創(chuàng)建新線程。3. 如果任務(wù)不能被放入隊(duì)列,就嘗試創(chuàng)建新線程,如果創(chuàng)建失敗,就拒絕此任務(wù)(reject)
Paste_Image.png
3)工作線程的run方法
ThreadPoolExecutor有兩個最重要的集合屬性,分別是存儲接收任務(wù)的任務(wù)隊(duì)列
Paste_Image.png
用來干活的集合
Paste_Image.png
worker是ThreadPoolExecutor的一個內(nèi)部類,實(shí)現(xiàn)了Runnable接口
Paste_Image.png
他的run方法:
Paste_Image.png
Paste_Image.png
可以看到工作線程就是在一直調(diào)用getTask方法獲取任務(wù),然后調(diào)用 task.run()方法執(zhí)行任務(wù),這里才是真正的執(zhí)行任務(wù)。這些操作全部是在while循環(huán)里,只要有任務(wù)就要一直執(zhí)行下去