一、使用線程池的好處oop
a、下降資源消耗。經過重複利用已建立的線程下降線程建立和摧毀形成的消耗;spa
b、提升響應速度。當任務到達時,任務能夠不須要等到線程建立就能當即執行;線程
c、提升線程的可管理性。線程是稀缺資源,若是無限制地建立,不只會消耗系統資源,還會下降系統的穩定性,使用線程池能夠及進行統一分配、調優和監控。rest
二、線程池的實現原理code
當線程池想提交一個任務以後,線程池的主要處理流程如圖:對象
jdk1.8中ThreadPoolExecutor執行execute()方法的源代碼以下:隊列
1 public void execute(Runnable command) { 2 if (command == null) 3 throw new NullPointerException(); 4 int c = ctl.get();//原子類型AtomicInteger ctl,獲取值 5 if (workerCountOf(c) < corePoolSize) {//判斷當前工做線程是否小於核心線程數目 6 if (addWorker(command, true))//是則建立新的工做線程,並將當前任務傳遞進去處理後返回結果, 7 return; 8 c = ctl.get();//若是失敗,繼續執行下面的代碼進行判斷 9 } 10 if (isRunning(c) && workQueue.offer(command)) { 11 int recheck = ctl.get(); 12 if (! isRunning(recheck) && remove(command)) 13 reject(command); 14 else if (workerCountOf(recheck) == 0) 15 addWorker(null, false);//加入工做線程 16 } 17 else if (!addWorker(command, false))//建立新的線程, 18 reject(command); 19 }
1 private boolean addWorker(Runnable firstTask, boolean core) { 2 retry: 3 for (;;) { 4 int c = ctl.get(); 5 int rs = runStateOf(c); 6 7 // Check if queue empty only if necessary. 8 if (rs >= SHUTDOWN && 9 ! (rs == SHUTDOWN && 10 firstTask == null && 11 ! workQueue.isEmpty())) 12 return false; 13 14 for (;;) { 15 int wc = workerCountOf(c); 16 if (wc >= CAPACITY || 17 wc >= (core ? corePoolSize : maximumPoolSize)) 18 return false; 19 if (compareAndIncrementWorkerCount(c)) 20 break retry; 21 c = ctl.get(); // Re-read ctl 22 if (runStateOf(c) != rs) 23 continue retry; 24 // else CAS failed due to workerCount change; retry inner loop 25 } 26 }
線程池中的線程執行任務分爲兩種狀況:ip
a、在execute()方法中建立一個線程時,會讓這個線程執行當前任務;資源
b、在這個線程執行完上述任務後,會反覆從BlockingQueue獲取任務來執行。rem
三、線程池的使用
咱們能夠經過ThreadPoolExecutor來建立一個線程池。
new ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler);
corePoolSize:線程池的基本大小,當提交一個任務到線程池時,線程池會建立一個線程來執行任務,即便其餘空閒的基本線程可以執行新任務也會建立線程,等到須要執行的任務數大於線程池基本大小時就再也不建立。若是調用了線程池的prestartAllCoreThreads()方法,線程池會提早建立並啓動全部基本線程。
maximumPoolSize:線程池的最大數量,線程池容許建立的最大線程數。若是隊列滿了,而且已建立的線程數小於最大線程數,則線程池會再建立新的線程執行任務。值得注意的是,若是使用了無界的任務隊列這個參數就沒什麼效果。
KeepAliveTime:線程活動保持時間,線程池的工做線程空閒後,保持存活的時間。
unit:線程活動保持時間的單位,可選的單位有天,小時,分鐘,毫秒,微秒,納秒。
workQueue:任務隊列,用來保存等待執行的任務的阻塞隊列。在任務被執行以前存儲這些任務,工做隊列僅存儲執行了execute方法的任務。能夠選擇如下幾個阻塞隊列:ArrayBlockingQueue,LinkedBlockingQueue,SynchronousQueue和PriorityBlockingQueue。
threadFactory:用於設置建立線程的工廠,能夠經過線程工廠給每一個建立出來的線程設置更有意義的名字。
handler:飽和策略,當隊列和線程池都滿了,說明線程池處於飽和狀態,那麼必須採起一種策略處理提交的新任務。這個策略默認狀況下是AbortPolicty,表示沒法處理新任務時拋出異常。
四、向線程池提交任務
可使用兩個方法向線程池提交任務,分別是execute()和submit()方法。
execute()方法用於提交不須要返回值的任務,因此沒法判斷任務是否被線程池執行成功。
submit()方法用於提交須要返回值的任務。線程池會返回一個future類型的對象,經過這個future對象能夠判斷任務是否執行成功,而且能夠經過future的get()方法來獲取返回值,get()方法會阻塞當前線程知道任務完成,而使用get(long timeout, TimeUnit unit)方法則會阻塞當前線程一段時間後當即返回,這時候可能任務尚未執行完。
五、關閉線程池
能夠經過調用線程池的shutdown或shutdownNow方法來關閉線程池。
原理:遍歷線程池中的工做線程,而後逐個調用線程的interrupt方法來中斷線程,因此沒法響應中斷的任務可能永遠沒法終止。
區別:shutdownNow先將線程池的狀態設置成STOP,而後嘗試中止全部正在執行或暫停任務的額線程,並返回等待執行任務的列表;
shutdown只是將線程池的狀態設置成SHUTDOWN狀態,而後中斷全部沒有正在執行任務的線程。
一般調用shutdown來關閉線程池,若是任務不必定要執行完,則能夠調用shutdownNow方法。
建議使用有界隊列:能增長系統的穩定性和預警能力。