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