Java中的線程池

一、使用線程池的好處oop

a、下降資源消耗。經過重複利用已建立的線程下降線程建立和摧毀形成的消耗;spa

b、提升響應速度。當任務到達時,任務能夠不須要等到線程建立就能當即執行;線程

c、提升線程的可管理性。線程是稀缺資源,若是無限制地建立,不只會消耗系統資源,還會下降系統的穩定性,使用線程池能夠及進行統一分配、調優和監控。rest

二、線程池的實現原理code

當線程池想提交一個任務以後,線程池的主要處理流程如圖:對象

clipboard.png

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方法。

建議使用有界隊列:能增長系統的穩定性和預警能力。

相關文章
相關標籤/搜索