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使用。