1. 程式人生 > >Java併發程式設計的藝術之九----執行緒池

Java併發程式設計的藝術之九----執行緒池

第一:降低資源消耗。通過重複利用已建立的執行緒降低執行緒建立和銷燬造成的消耗

第二:提高響應速度。當任務到達時,任務可以不需要等到執行緒建立就能立即執行

第三:提高執行緒的可管理性。執行緒是稀缺資源,如果無限制地建立,不僅會消耗系統資源,

還會降低系統的穩定性,使用執行緒池可以進行統一分配、調優和監控。但是,要做到合理利用執行緒池,必須對其實現原理了如指掌。

1.執行緒池的實現原理

從圖中可以看出,當提交一個新任務到執行緒池時,執行緒池的處理流程如下。

1)執行緒池判斷核心執行緒池裡的執行緒是否都在執行任務。如果不是,則建立一個新的工作執行緒來執行任務。如果核心執行緒池裡的執行緒都在執行任務,則進入下個流程。

2)執行緒池判斷工作佇列是否已經滿。如果工作佇列沒有滿,則將新提交的任務儲存在這個工作佇列裡。如果工作佇列滿了,則進入下個流程。

3)執行緒池判斷執行緒池的執行緒是否都處於工作狀態。如果沒有,則建立一個新的工作執行緒來執行任務。如果已經滿了,則交給飽和策略來處理這個任務。

Execute方法執行過程

①如果當前執行執行緒少於核心執行緒的容量,就建立新執行緒執行任務(獲取全域性鎖)

②如果執行執行緒等於或多於核心執行緒容量,就將任務加入阻塞佇列

③如果阻塞佇列已滿,建立新執行緒處理任務

④如果超過最大執行緒數maximumPoolSize,任務將被拒絕,呼叫RejectedExecutionHandler.rejectedExecution()方法。

執行execute()方法時,儘可能避免獲取全域性鎖,如果當前執行執行緒數大於等於corePoolSize,幾乎所有的execute方法都是執行步驟2,不需要獲取全域性鎖

 

工作執行緒:執行緒池建立執行緒時,會將執行緒封裝成工作執行緒worker,worker執行完任務後,還會迴圈獲取工作佇列的任務來執行。

①execute方法建立一個執行緒時,會讓這個執行緒執行當前任務

②這個執行緒執行完上圖1的任務後,會反覆從BlockingQueue獲取任務執行

 

 

2.執行緒池的使用

2.1執行緒池的建立

可以通過ThreadPoolExecutor來建立一個執行緒池。

new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, milliseconds, runnableTaskQueue, handler);

①corePoolSize(核心執行緒池的基本大小):當提交一個任務到執行緒池時,執行緒池會建立一個執行緒來執行任務,即使其他空閒的基本執行緒能夠執行新任務也會建立執行緒,等到需要執行的任務數大於核心執行緒池基本大小時就不再建立。

②runnableTaskQueue(任務佇列):用於儲存等待執行的任務阻塞佇列

ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue、PriorityBlockingQueue無界

③maximumPoolSize:執行緒池允許建立的最大執行緒數。如果佇列滿了,並且已建立的執行緒數小於最大執行緒數,則執行緒池會再建立新的執行緒執行任務。無界佇列沒有效果

④ThreadFactory:用於設定建立執行緒的工廠,可以通過執行緒工廠給每個創建出來的執行緒設定更有意義的名字。

⑤RejectedExecutionHandler(飽和策略):當佇列和執行緒池都滿了,說明執行緒池處於飽和狀態,那麼必須採取一種策略處理提交的新任務。這個策略預設情況下是AbortPolicy,表示無法處理新任務時丟擲異常。

keepAliveTime(執行緒活動保持時間):執行緒池的工作執行緒空閒後,保持存活的時間。所以,如果任務很多,並且每個任務執行的時間比較短,可以調大時間,提高執行緒的利用率

TimeUnit(執行緒活動保持時間的單位):可選的單位有天(DAYS)、小時(HOURS)、分鐘(MINUTES)、毫秒(MILLISECONDS)、微秒(MICROSECONDS,千分之一毫秒)和納秒(NANOSECONDS,千分之一微秒)

2.2 向執行緒池提交任務

Execute和submit

execute()方法用於提交不需要返回值的任務,所以無法判斷任務是否被執行緒池執行成功。

threadsPool.execute(new Runnable() {

@Override

public void run() {

// TODO Auto-generated method stub

}

});

 

 

submit()方法用於提交需要返回值的任務

一個future型別的物件,通過這個future物件可以判斷任務是否執行成功,並且可以通過future的get()方法來獲取返回值,get()方法會阻塞當前執行緒直到任務完成,

2.3執行緒池的監控

TaskCount:執行緒池需要執行的任務數

completeTaskCount:已完成的任務數

largestPoolSize:執行緒池裡曾經建立過的最大執行緒數

getPoolSize:執行緒池的執行緒數量