您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“springboot為異步任務規(guī)劃自定義線程池如何實現(xiàn)”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“springboot為異步任務規(guī)劃自定義線程池如何實現(xiàn)”吧!
線程池的作用
防止資源占用無限的擴張
調(diào)用過程省去資源的創(chuàng)建和銷毀所占用的時間
在高并發(fā)環(huán)境下,不斷的分配新資源,可能導致系統(tǒng)資源耗盡。所以為了避免這個問題,我們?yōu)楫惒饺蝿找?guī)劃一個線程池。當然,如果沒有配置線程池的話,springboot會自動配置一個ThreadPoolTaskExecutor 線程池到bean當中。
# 核心線程數(shù) spring.task.execution.pool.core-size=8 # 最大線程數(shù) spring.task.execution.pool.max-size=16 # 空閑線程存活時間 spring.task.execution.pool.keep-alive=60s # 是否允許核心線程超時 spring.task.execution.pool.allow-core-thread-timeout=true # 線程隊列數(shù)量 spring.task.execution.pool.queue-capacity=100 # 線程關(guān)閉等待 spring.task.execution.shutdown.await-termination=false spring.task.execution.shutdown.await-termination-period= # 線程名稱前綴 spring.task.execution.thread-name-prefix=task-
在springboot配置文件中加入上面的配置,即可實現(xiàn)ThreadPoolTaskExecutor 線程池。
有的時候,我們希望將系統(tǒng)內(nèi)的一類任務放到一個線程池,另一類任務放到另外一個線程池,所以使用Spring Boot自帶的任務線程池就捉襟見肘了。下面介紹自定義線程池的方法。
創(chuàng)建一個 線程池配置類 TaskConfiguration ,并配置一個 任務線程池對象 taskExecutor。
@Configuration public class TaskConfiguration { @Bean("taskExecutor") public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(20); executor.setQueueCapacity(200); executor.setKeepAliveSeconds(60); executor.setThreadNamePrefix("taskExecutor-"); executor.setRejectedExecutionHandler(new CallerRunsPolicy()); return executor; } }
上面我們通過使用 ThreadPoolTaskExecutor 創(chuàng)建了一個 線程池,同時設(shè)置了以下這些參數(shù):
線程池屬性 | 屬性的作用 | 上文代碼設(shè)置初始值 |
---|---|---|
核心線程數(shù)CorePoolSize | 線程池創(chuàng)建時候初始化的線程數(shù),最小線程數(shù) | 10 |
最大線程數(shù)MaxPoolSize | 線程池最大的線程數(shù),只有在緩沖隊列滿了之后,才會申請超過核心線程數(shù)的線程 | 20 |
緩沖任務隊列QueueCapacity | 用來緩沖執(zhí)行任務的隊列 | 200 |
允許線程的空閑時間KeepAliveSeconds | 超過了核心線程之外的線程,在空閑時間到達之后,沒活干的線程會被銷毀 | 60秒 |
線程池名的前綴 ThreadNamePrefix | 可以用于定位處理任務所在的線程池 | taskExecutor- |
線程池對任務的Reject策略RejectedExecutionHandler | 當線程池運行飽和,或者線程池處于shutdown臨界狀態(tài)時,用來拒絕一個任務的執(zhí)行 | CallerRunsPolicy |
Reject策略預定義有四種:
AbortPolicy,用于被拒絕任務的處理程序,它將拋出RejectedExecutionException。
CallerRunsPolicy,用于被拒絕任務的處理程序,它直接在execute方法的調(diào)用線程中運行被拒絕的任務。
DiscardOldestPolicy,用于被拒絕任務的處理程序,它放棄最舊的未處理請求,然后重試execute。
DiscardPolicy,用于被拒絕任務的處理程序,默認情況下它將丟棄被拒絕的任務。
創(chuàng)建 AsyncExecutorTask類,三個任務的配置和 AsyncTask 一樣,不同的是 @Async 注解需要指定前面配置的 線程池的名稱 taskExecutor。
@Component public class AsyncExecutorTask extends AbstractTask { @Async("taskExecutor") public Future<String> doTaskOneCallback() throws Exception { super.doTaskOne(); System.out.println("任務一,當前線程:" + Thread.currentThread().getName()); return new AsyncResult<>("任務一完成"); } @Async("taskExecutor") public Future<String> doTaskTwoCallback() throws Exception { super.doTaskTwo(); System.out.println("任務二,當前線程:" + Thread.currentThread().getName()); return new AsyncResult<>("任務二完成"); } @Async("taskExecutor") public Future<String> doTaskThreeCallback() throws Exception { super.doTaskThree(); System.out.println("任務三,當前線程:" + Thread.currentThread().getName()); return new AsyncResult<>("任務三完成"); } }
在 單元測試 用例中,注入 AsyncExecutorTask 對象,并在測試用例中執(zhí)行 doTaskOne(),doTaskTwo(),doTaskThree() 三個方法。
@SpringBootTest public class AsyncExecutorTaskTest { @Autowired private AsyncExecutorTask task; @Test public void testAsyncExecutorTask() throws Exception { task.doTaskOneCallback(); task.doTaskTwoCallback(); task.doTaskThreeCallback(); sleep(30 * 1000L); } }
執(zhí)行一下上述的 單元測試,可以看到如下結(jié)果:
開始做任務一
開始做任務三
開始做任務二
完成任務二,耗時:3905毫秒
任務二,當前線程:taskExecutor-2
完成任務一,耗時:6184毫秒
任務一,當前線程:taskExecutor-1
完成任務三,耗時:9737毫秒
任務三,當前線程:taskExecutor-3
執(zhí)行上面的單元測試,觀察到 任務線程池 的 線程池名的前綴 被打印,說明 線程池 成功執(zhí)行 異步任務!
由于在應用關(guān)閉的時候異步任務還在執(zhí)行,導致類似 數(shù)據(jù)庫連接池 這樣的對象一并被 銷毀了,當 異步任務 中對 數(shù)據(jù)庫 進行操作就會出錯。
解決方案如下,重新設(shè)置線程池配置對象,新增線程池 setWaitForTasksToCompleteOnShutdown() 和 setAwaitTerminationSeconds() 配置:
@Bean("taskExecutor") public Executor taskExecutor() { ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler(); executor.setPoolSize(20); executor.setThreadNamePrefix("taskExecutor-"); executor.setWaitForTasksToCompleteOnShutdown(true); executor.setAwaitTerminationSeconds(60); return executor; }
setWaitForTasksToCompleteOnShutdown(true): 該方法用來設(shè)置 線程池關(guān)閉 的時候 等待 所有任務都完成后,再繼續(xù) 銷毀 其他的 Bean,這樣這些 異步任務 的 銷毀 就會先于 數(shù)據(jù)庫連接池對象 的銷毀。
setAwaitTerminationSeconds(60): 該方法用來設(shè)置線程池中 任務的等待時間,如果超過這個時間還沒有銷毀就 強制銷毀,以確保應用最后能夠被關(guān)閉,而不是阻塞住。
異步任務** 的 銷毀 就會先于 數(shù)據(jù)庫連接池對象 的銷毀。
setAwaitTerminationSeconds(60): 該方法用來設(shè)置線程池中 任務的等待時間,如果超過這個時間還沒有銷毀就 強制銷毀,以確保應用最后能夠被關(guān)閉,而不是阻塞住。
到此,相信大家對“springboot為異步任務規(guī)劃自定義線程池如何實現(xiàn)”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學習!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。