上一篇文章中我們學會了如何使用異步的方式去執(zhí)行任務(wù),在實際的開發(fā)當中,應(yīng)用服務(wù)的并發(fā)量比較大時,頻繁的創(chuàng)建和銷毀線程是非常消耗性能和資源的,并且一個進程能夠創(chuàng)建的線程數(shù)量也是有上限的。為了解決這些問題,我們需要使用線程池來管理這些業(yè)務(wù)線程。 如果沒有配置線程池,springboot會自動配置一個ThreadPoolTaskExecutor線程池到bean當中。 spring: task: execution: pool: # 核心線程數(shù) core-size: 8 # 最大線程數(shù) max-size: 16 # 空閑線程存活時間 keep-alive: 60s # 是否允許核心線程超時 allow-core-thread-timeout: true # 線程隊列數(shù)量 queue-capacity: 100 shutdown: # 關(guān)閉等待 await-termination: false await-termination-period: # 前綴名稱 thread-name-prefix: task-1234567891011121314151617181920復制代碼類型:[java] 自定義線程池有時候我們希望將線程放到不同的線程池進行分類,或者有一些個性化的需求。這時我們就可以創(chuàng)建一個線程池配置類并配置一個任務(wù)線程池對象。 package com.example.demo.configuration;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.Executor;import java.util.concurrent.ThreadPoolExecutor;@Configurationpublic class TaskConfiguration { @Bean("taskExecutor") public Executor taskExecutor() { // 創(chuàng)建線程池 ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 核心線程數(shù)、線程池創(chuàng)建時候初始化的線程數(shù),最小線程數(shù) executor.setCorePoolSize(10); // 線程池最大的線程數(shù)(只有在緩沖隊列滿了之后,才會申請超過核心線程數(shù)的線程) executor.setMaxPoolSize(20); // 用來緩沖執(zhí)行任務(wù)的隊列 executor.setQueueCapacity(200); // 超過了核心線程之外的線程,在空閑時間到達之后,沒活干的線程會被銷毀 executor.setKeepAliveSeconds(60); // 定位處理任務(wù)所在的線程池 executor.setThreadNamePrefix("taskExecutor-"); // 線程池對任務(wù)的Reject策略,當線程池運行飽和,或者線程池處于shutdown臨界狀態(tài)時,用來拒絕一個任務(wù)的執(zhí)行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); return executor; } }123456789101112131415161718192021222324252627282930復制代碼類型:[java] 注釋中提到的Reject策略一共有四種: AbortPolicy 將拋出RejectedExecutionException CallerRunsPolicy 直接在execute方法的調(diào)用線程中運行被拒絕的任務(wù) DiscardOldestPolicy 放棄最舊的未處理請求,然后重試execute DiscardPolicy 默認情況下它將丟棄被拒絕的任務(wù) 創(chuàng)建AsyncExecutorTask類繼承TaskMethodProvider,@Async注解需要指定前面配置的線程池的名稱taskExecutor: package com.example.demo.task;import org.springframework.scheduling.annotation.Async;import org.springframework.scheduling.annotation.AsyncResult;import org.springframework.stereotype.Component;@Componentpublic class AsyncExecutorTask extends TaskMethodProvider { @Async("taskExecutor") public void doTaskOneCallback() throws Exception { super.taskOne(); System.out.println("任務(wù)一,當前線程:" + Thread.currentThread().getName()); new AsyncResult<>("任務(wù)一完成"); } @Async("taskExecutor") public void doTaskTwoCallback() throws Exception { super.taskTwo(); System.out.println("任務(wù)二,當前線程:" + Thread.currentThread().getName()); new AsyncResult<>("任務(wù)二完成"); } @Async("taskExecutor") public void doTaskThreeCallback() throws Exception { super.taskThree(); System.out.println("任務(wù)三,當前線程:" + Thread.currentThread().getName()); new AsyncResult<>("任務(wù)三完成"); } }123456789101112131415161718192021222324252627282930復制代碼類型:[java] 編寫單元測試: package com.example.demo;import com.example.demo.task.AsyncExecutorTask;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import static java.lang.Thread.sleep;@SpringBootTestpublic class Task { @Autowired private AsyncExecutorTask task; @Test public void testAsyncExecutorTask() throws Exception { task.doTaskOneCallback(); task.doTaskTwoCallback(); task.doTaskThreeCallback(); sleep(10 * 1000L); } }1234567891011121314151617181920212223復制代碼類型:[java] 執(zhí)行單元測試: 線程池成功執(zhí)行異步任務(wù)。 關(guān)閉線程池在原有TaskConfiguration.java代碼的基礎(chǔ)上添加: executor.setWaitForTasksToCompleteOnShutdown(true); executor.setAwaitTerminationSeconds(60);12復制代碼類型:[java] setWaitForTasksToCompleteOnShutdown(true): 線程池關(guān)閉的時候等待所有任務(wù)都完成后,再繼續(xù)銷毀其他的Bean,使異步任務(wù)的銷毀就會先于數(shù)據(jù)庫連接池對象的銷毀。 setAwaitTerminationSeconds(60): 設(shè)置線程任務(wù)等待時間,超過這個時間任務(wù)還沒有銷毀就強制銷毀。 @Scheduled實現(xiàn)定時任務(wù)@Scheduled實現(xiàn)定時任務(wù)是SpringBoot自身提供的功能,不需要maven依賴,只需要在啟動類上添加@EnableScheduling注解,即可開啟定時任務(wù)。 下面來實現(xiàn)一個定時任務(wù),在task文件夾下創(chuàng)建ScheduledTask.java: package com.example.demo.task;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;import java.util.Date;@Componentpublic class ScheduledTask { // 方法執(zhí)行完成后3秒再開始執(zhí)行 @Scheduled(fixedDelay = 3000) public void fixedDelayJob() throws InterruptedException { System.out.println("fixedDelay 開始:" + new Date()); Thread.sleep(10 * 1000); System.out.println("fixedDelay 結(jié)束:" + new Date()); } // 每隔2秒 @Scheduled(fixedRate = 2000) public void fixedRateJob() throws InterruptedException { System.out.println("===========fixedRate 開始:" + new Date()); Thread.sleep(5 * 1000); System.out.println("===========fixedRate 結(jié)束:" + new Date()); } // 每隔7秒執(zhí)行一次 @Scheduled(cron = "0/7 * * * * ? ") public void cronJob() { System.out.println("=========================== ...>>cron...." + new Date()); } }12345678910111213141516171819202122232425262728293031復制代碼類型:[java] 如果只是這樣編寫所有的定時任務(wù)使用的都是一個線程,不能得到我們想要的結(jié)果,所以需要解決解決定時任務(wù)單線程運行的問題。 在config文件夾下創(chuàng)建ScheduleConfig.java: package com.example.demo.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.annotation.EnableScheduling;import org.springframework.scheduling.annotation.SchedulingConfigurer;import org.springframework.scheduling.config.ScheduledTaskRegistrar;import java.util.concurrent.Executor;import java.util.concurrent.Executors;@Configuration@EnableSchedulingpublic class ScheduleConfig implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { taskRegistrar.setScheduler(scheduledTaskExecutor()); } @Bean public Executor scheduledTaskExecutor() { // 線程池的大小為3 return Executors.newScheduledThreadPool(3); } }1234567891011121314151617181920212223242526復制代碼類型:[java] 執(zhí)行代碼,得到打印信息: 在@Scheduled標簽后面括號中的fixedDelay和fixedRate單位都是毫秒,區(qū)別是fixedDelay任務(wù)執(zhí)行完畢后一段時間再次執(zhí)行而fixedRate則是每隔多長時間就執(zhí)行一次。 @Scheduled標簽中還可以使用cron表達式:
cron特殊符號:
|
|
來自: 碼農(nóng)9527 > 《Java》