1. 程式人生 > >Spring中的執行緒池

Spring中的執行緒池

前言:

 

Java SE 5.0引入了ThreadPoolExecutor、ScheduledThreadPoolExecutor。Spring 2.x藉助ConcurrentTaskExecutor和ThreadPoolTaskExecutor能夠通過IoC配置形式自定義它們暴露的各個屬性。

 

多執行緒併發處理起來通常比較麻煩,如果你使用spring容器來管理業務bean,事情就好辦了多了。spring封裝了java的多執行緒的實現,你只需要關注於併發事物的流程以及一些併發負載量等特性,具體來說如何使用spring來處理併發事務:

 

1、瞭解 TaskExecutor介面

 

Spring的TaskExecutor介面等同於java.util.concurrent.Executor介面。 實際上,它存在的主要原因是為了在使用執行緒池的時候,將對Java 5的依賴抽象出來。 這個介面只有一個方法execute(Runnable task),它根據執行緒池的語義和配置,來接受一個執行任務。

 

最初建立TaskExecutor是為了在需要時給其他Spring元件提供一個執行緒池的抽象。 例如ApplicationEventMulticaster元件、JMS的 AbstractMessageListenerContainer和對Quartz的整合都使用了TaskExecutor抽象來提供執行緒池。 當然,如果你的bean需要執行緒池行為,你也可以使用這個抽象層。

 

2、TaskExecutor介面的實現類

 

SimpleAsyncTaskExecutor 類

 

這個實現不重用任何執行緒,或者說它每次呼叫都啟動一個新執行緒。但是,它還是支援對併發總數設限,當超過執行緒併發總數限制時,阻塞新的呼叫,直到有位置被釋放。如果你需要真正的池,請繼續往下看。

 

SyncTaskExecutor類

 

這個實現不會非同步執行。相反,每次呼叫都在發起呼叫的執行緒中執行。它的主要用處是在不需要多執行緒的時候,比如簡單的test case。

 

ConcurrentTaskExecutor 類

 

這個實現是對Java 5 java.util.concurrent.Executor類的包裝。有另一個備選, ThreadPoolTaskExecutor類,它暴露了Executor的配置引數作為bean屬性。很少需要使用ConcurrentTaskExecutor, 但是如果ThreadPoolTaskExecutor不敷所需,ConcurrentTaskExecutor是另外一個備選。

 

<bean id="concurrentTaskExecutor" 
       class="org.springframework.scheduling.concurrent.ConcurrentTaskExecutor"/>

 

SimpleThreadPoolTaskExecutor 類

 

這個實現實際上是Quartz的SimpleThreadPool類的子類,它會監聽Spring的生命週期回撥。當你有執行緒池,需要在Quartz和非Quartz元件中共用時,這是它的典型用處。

 

ThreadPoolTaskExecutor 類

 

它不支援任何對java.util.concurrent包的替換或者下行移植。Doug Lea和Dawid Kurzyniec對java.util.concurrent的實現都採用了不同的包結構,導致它們無法正確執行。 

 

這個實現只能在Java 5環境中使用,但是卻是這個環境中最常用的。它暴露的bean properties可以用來配置一個java.util.concurrent.ThreadPoolExecutor,把它包裝到一個TaskExecutor中。如果你需要更加先進的類,比如ScheduledThreadPoolExecutor,我們建議你使用ConcurrentTaskExecutor來替代。

 

下面先學習下JDK中的ThreadPoolExecutor中的相關資訊.ThreadPoolExecutor建構函式如下: 

 

public ThreadPoolExecutor(int corePoolSize,  
   int maximumPoolSize, long keepAliveTime,  
   TimeUnit unit, BlockingQueue<Runnable> workQueue,  
   ThreadFactory threadFactory,  
   RejectedExecutionHandler handler) {}

 

下面分別說下各項代表的具體意義: 

 

int corePoolSize

執行緒池維護執行緒的最小數量. 


int maximumPoolSize

執行緒池維護執行緒的最大數量. 


long keepAliveTime

空閒執行緒的存活時間. 


TimeUnit unit

時間單位,現有納秒,微秒,毫秒,秒列舉值. 

 

BlockingQueue<Runnable>  workQueue

持有等待執行的任務佇列. 

 

RejectedExecutionHandler handler

用來拒絕一個任務的執行,有兩種情況會發生這種情況:


一是在execute方法中若addIfUnderMaximumPoolSize(command)為false,即執行緒池已經飽和; 


二是在execute方法中, 發現runState!=RUNNING || poolSize == 0,即已經shutdown,就呼叫ensureQueuedTaskHandled(Runnable command),在該方法中有可能呼叫reject。

 

Reject策略預定義有四種: 

 

 

ThreadPoolExecutor執行器的處理流程: 

 

(1)當執行緒池大小小於corePoolSize就新建執行緒,並處理請求. 
(2)當執行緒池大小等於corePoolSize,把請求放入workQueue中,池子裡的空閒執行緒就去從workQueue中取任務並處理. 
(3)當workQueue放不下新入的任務時,新建執行緒加入執行緒池,並處理請求,如果池子大小撐到了maximumPoolSize就用RejectedExecutionHandler來做拒絕處理. 
(4)另外,當執行緒池的執行緒數大於corePoolSize的時候,多餘的執行緒會等待keepAliveTime長的時間,如果無請求可處理就自行銷燬. 

 

瞭解清楚了ThreadPoolExecutor的執行流程,開頭提到的org.springframework.core.task.TaskRejectedException異常也就好理解和解決了.ThreadPoolTaskExecutor類中使用的 
就是ThreadPoolExecutor.AbortPolicy()策略,直接丟擲異常. 

 

spring中ThreadPoolTaskExecutor最常用方式就是做為BEAN注入到容器中,其暴露的各個屬性其實是ThreadPoolExecutor的屬性,而且這體現了DI容器的優勢。如下程式碼: 

 

<bean id="threadPoolTaskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">  
   <property name="corePoolSize" value="2"/>  
   <property name="keepAliveSeconds" value="200"/>  
   <property name="maxPoolSize" value="10"/>  
   <property name="queueCapacity" value="60"/>  
</bean>

 

TimerTaskExecutor類

 

這個實現使用一個TimerTask作為其背後的實現。它和SyncTaskExecutor的不同在於,方法呼叫是在一個獨立的執行緒中進行的,雖然在那個執行緒中是同步的。

 

WorkManagerTaskExecutor類

 

這個實現使用了CommonJ WorkManager作為其底層實現,是在Spring context中配置CommonJ WorkManager應用的最重要的類。和SimpleThreadPoolTaskExecutor類似,這個類實現了WorkManager介面,因此可以直接作為WorkManager使用。