配置說明:
從Spring 3.0開始,有一個用於配置TaskExecutor和TaskScheduler實例的XML命名空間。它還提供了一種方便的方法來配置要使用觸發器安排的任務。
任務調度器的配置詳細參數說明:
task:scheduler/@pool-size:調度線程池的大小,調度線程在被調度任務完成前不會空閑
task:scheduled/@cron:cron表達式,注意,若上次任務未完成,即使到了下一次調度時間,任務也不會重復調度
<task:scheduled-tasks scheduler="scheduler"> <task:scheduled ref="beanID" method="methodName" cron="CronExp" /> </task:scheduled-tasks> <task:scheduler id="scheduler" pool-size="10" />
任務執行器配置詳細參數說明:
task:executor/@pool-size:可以指定執行線程池的初始大小、最大大小
task:executor/@queue-capacity:等待執行的任務隊列的容量
task:executor/@rejection-policy:當等待隊列爆了時的策略,分為丟棄、由任務執行器直接運行等方式
<task:executor id="executor" keep-alive="3600" pool-size="100-200" queue-capacity="500" rejection-policy="CALLER_RUNS" />
從該配置中可以看出,還提供了“隊列容量”值。還應根據執行程序的隊列容量來考慮線程池的配置。有關池大小和隊列容量之間關系的完整描述,請參閱ThreadPoolExecutor的文檔。主要思想是,當提交任務時,如果活動線程的數量當前小於核心大小,則執行程序將首先嘗試使用空閑線程。如果已達到核心大小,則只要尚未達到其容量,任務就會添加到隊列中。只有這樣,如果已達到隊列的容量,執行程序是否會創建超出核心大小的新線程。如果還達到了最大大小,則執行程序將拒絕該任務。
默認情況下,隊列是無限制的,但這很少是所需的配置,因為如果在所有池線程忙的情況下將足夠的任務添加到該隊列,則可能導致OutOfMemoryErrors。此外,如果隊列是無界的,那么最大大小根本沒有影響。由於執行器將始終在創建超出核心大小的新線程之前嘗試隊列,因此隊列必須具有有限的容量,以使線程池增長超出核心大小(這就是為什么固定大小的池是使用時唯一合理的情況一個無限的隊列)。
稍后,我們將回顧保持活動設置的效果,這增加了在提供池大小配置時要考慮的另一個因素。首先,如上所述,讓我們考慮一個任務被拒絕的情況。默認情況下,當任務被拒絕時,線程池執行程序將拋出TaskRejectedException。但是,拒絕策略實際上是可配置的。使用默認拒絕策略(AbortPolicy實現)時會拋出異常。對於可以在高負載下跳過某些任務的應用程序,可以配置DiscardPolicy或DiscardOldestPolicy。另一個適用於需要在高負載下限制提交的任務的應用程序的選項是CallerRunsPolicy。該策略不會拋出異常或丟棄任務,而只是強制調用submit方法的線程自己運行任務。這個想法是這樣的調用者在運行該任務時會很忙,而不能 立即提交其他任務。 因此,它提供了一種簡單的方法來限制傳入的負載,同時保持線程池和隊列的限制。 通常,這允許執行程序“趕上”它正在處理的任務,從而釋放隊列,池中或兩者中的一些容量。 可以從'executor'元素上'rejection-policy'屬性的可用值枚舉中選擇任何這些選項。
最后,keep-alive設置確定線程在終止之前可以保持空閑的時間限制(以秒為單位)。如果池中當前有多個線程核心數,則在等待這段時間而不處理任務后,多余的線程將被終止。時間值為零將導致多余線程在執行任務后立即終止,而不會在任務隊列中保留后續工作。
<task:annotation-driven executor="taskExecutor" scheduler="taskScheduler"/>
還有別的一種配置:
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> <!-- 線程池維護線程的最少數量 --> <property name="corePoolSize" value="${taskExecutor.corePoolSize}" /> <!-- 允許的空閑時間 --> <property name="keepAliveSeconds" value="${taskExecutor.keepAliveSeconds}" /> <!-- 線程池維護線程的最大數量 --> <property name="maxPoolSize" value="${taskExecutor.maxPoolSize}" /> <!-- 緩存隊列 --> <property name="queueCapacity" value="${taskExecutor.queueCapacity}" /> <!-- 對拒絕task的處理策略 --> <property name="rejectedExecutionHandler"> <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy" /> <!-- AbortPolicy:直接拋出java.util.concurrent.RejectedExecutionException異常 --> <!-- CallerRunsPolicy:主線程直接執行該任務,執行完之后嘗試添加下一個任務到線程池中,可以有效降低向線程池內添加任務的速度 --> <!-- DiscardOldestPolicy:拋棄舊的任務、暫不支持;會導致被丟棄的任務無法再次被執行 --> <!-- DiscardPolicy:拋棄當前任務、暫不支持;會導致被丟棄的任務無法再次被執行 --> </property> </bean> <task:annotation-driven executor="taskExecutor" scheduler="taskScheduler"/> <task:scheduler id="taskScheduler" pool-size="5"/>
屬性字段說明
corePoolSize:線程池維護線程的最少數量
keepAliveSeconds:允許的空閑時間
maxPoolSize:線程池維護線程的最大數量
queueCapacity:緩存隊列
rejectedExecutionHandler:對拒絕task的處理策略
execute(Runable)方法執行過程
如果此時線程池中的數量小於corePoolSize,即使線程池中的線程都處於空閑狀態,也要創建新的線程來處理被添加的任務。
如果此時線程池中的數量等於 corePoolSize,但是緩沖隊列 workQueue未滿,那么任務被放入緩沖隊列。
如果此時線程池中的數量大於corePoolSize,緩沖隊列workQueue滿,並且線程池中的數量小於maxPoolSize,建新的線程來處理被添加的任務。
如果此時線程池中的數量大於corePoolSize,緩沖隊列workQueue滿,並且線程池中的數量等於maxPoolSize,那么通過handler所指定的策略來處理此任務。也就是:處理任務的優先級為:核心線程corePoolSize、任務隊列workQueue、最大線程 maximumPoolSize,如果三者都滿了,使用handler處理被拒絕的任務。
當線程池中的線程數量大於corePoolSize時,如果某線程空閑時間超過keepAliveTime,線程將被終止。這樣,線程池可以動態的調整池中的線程數。