SpringBoot中的異步執(zhí)行方法詳解
源碼跟蹤
簡單描述
在SpringBoot2.0.9之前需要手動自定義線程池(如下2.1), 然后指定線程池的名稱
SpringBoot2.0.9以及之前的版本,使用的線程池默認是SimpleAsyncTaskExcutor, 之后的版本使用的是ThreadpoolTaskExecutor
并且不需要手動的創(chuàng)建當前線程池(但往往我們還是會手動指定,具體原因看源碼就可以自有判斷 )
SpringBoot會自動的掃描兩個文件下的配置信息:
所以如果我們寫的配置類想讓SpringBoot自動掃描到就可以放到兩個中的任意一個
我們項目中就是這樣使用的:在 spring.factories文件中指定一些配置類相對路徑,這樣配置類中的指定的Bean就可以放入到IOC容器中了
SpringBoot在org.springframework.boot.autoconfigure.AutoConfiguration.imports118行配置了TaskExecutionAutoConfiguration的位置,這樣SpringBoot就可以掃描到當前配置類
TaskExecutionAutoConfiguration
配置類信息如下
@ConditionalOnClass({ThreadPoolTaskExecutor.class}) // 代表如果容器中有這個類,就不在創(chuàng)建 @AutoConfiguration @EnableConfigurationProperties({TaskExecutionProperties.class}) // 配置文件 public class TaskExecutionAutoConfiguration { // 應用程序任務執(zhí)行器任務名稱 applicationTaskExecutor public static final String APPLICATION_TASK_EXECUTOR_BEAN_NAME = "applicationTaskExecutor"; public TaskExecutionAutoConfiguration() { } @Bean @ConditionalOnMissingBean public TaskExecutorBuilder taskExecutorBuilder(TaskExecutionProperties properties, ObjectProvider<TaskExecutorCustomizer> taskExecutorCustomizers, ObjectProvider<TaskDecorator> taskDecorator) { Pool pool = properties.getPool(); TaskExecutorBuilder builder = new TaskExecutorBuilder(); builder = builder.queueCapacity(pool.getQueueCapacity()); builder = builder.corePoolSize(pool.getCoreSize()); builder = builder.maxPoolSize(pool.getMaxSize()); builder = builder.allowCoreThreadTimeOut(pool.isAllowCoreThreadTimeout()); builder = builder.keepAlive(pool.getKeepAlive()); Shutdown shutdown = properties.getShutdown(); builder = builder.awaitTermination(shutdown.isAwaitTermination()); builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod()); builder = builder.threadNamePrefix(properties.getThreadNamePrefix()); Stream var10001 = taskExecutorCustomizers.orderedStream(); var10001.getClass(); builder = builder.customizers(var10001::iterator); builder = builder.taskDecorator((TaskDecorator)taskDecorator.getIfUnique()); return builder; } @Lazy @Bean( name = {"applicationTaskExecutor", "taskExecutor"} ) @ConditionalOnMissingBean({Executor.class}) public ThreadPoolTaskExecutor applicationTaskExecutor(TaskExecutorBuilder builder) { return builder.build(); }
TaskExecutionProperties
配置文件中
定義了線程名 task -
ThreadPoolTaskExecutor
public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport implements AsyncListenableTaskExecutor, SchedulingTaskExecutor { private final Object poolSizeMonitor = new Object(); private int corePoolSize = 1; private int maxPoolSize = Integer.MAX_VALUE; private int keepAliveSeconds = 60; private int queueCapacity = Integer.MAX_VALUE; private boolean allowCoreThreadTimeOut = false; private boolean prestartAllCoreThreads = false; // ...... ......................省略 // 創(chuàng)建代碼 @Override protected ExecutorService initializeExecutor( ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) { BlockingQueue<Runnable> queue = createQueue(this.queueCapacity); ThreadPoolExecutor executor; if (this.taskDecorator != null) { // 還是 new ThreadPoolExecutor executor = new ThreadPoolExecutor( this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler) { @Override public void execute(Runnable command) { Runnable decorated = taskDecorator.decorate(command); if (decorated != command) { decoratedTaskMap.put(decorated, command); } super.execute(decorated); } }; } else { executor = new ThreadPoolExecutor( this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler); } if (this.allowCoreThreadTimeOut) { executor.allowCoreThreadTimeOut(true); } if (this.prestartAllCoreThreads) { executor.prestartAllCoreThreads(); } this.threadPoolExecutor = executor; return executor; }
測試代碼:
// 注入 @Autowired private ThreadPoolTaskExecutor executor; @Test public void testThreadPool(){ System.out.println(executor); System.out.println("默認前綴:"+executor.getThreadNamePrefix()); System.out.println("默認核心線程數(shù):"+executor.getCorePoolSize()); System.out.println("默認最大線程數(shù):"+executor.getMaxPoolSize()); System.out.println("當前活躍線程數(shù):"+executor.getActiveCount()); System.out.println("臨時線程空閑時間:"+executor.getKeepAliveSeconds()); System.out.println("隊列最大值:"+executor.getQueueCapacity()); System.out.println("隊列數(shù)量:"+executor.getQueueSize()); }
結(jié)果如下:
org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor@7410c197
默認前綴:task-
默認核心線程數(shù):8
默認最大線程數(shù):2147483647
當前活躍線程數(shù):0
臨時線程空閑時間:60
隊列最大值:2147483647
隊列數(shù)量:0
我們可以看到SpringBoot中默認配置的線程池的數(shù)量, 很不符合我們的實際要求, 而且還容易發(fā)生OOM(Out Of Memory)
所以我們一般是手動指定線程池中的信息
SpringBoot異步執(zhí)行方法
定義一個配置類
SpringBoot底層對手動注入的Bean采用的名稱如果不在@Bean注解后面指定默認采用的是方法名
即: 這里的 generateExchangeCodeExecutor
@Slf4j @Configuration public class PromotionConfig { @Bean public Executor generateExchangeCodeExecutor(){ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 1.核心線程池大小 executor.setCorePoolSize(2); // 2.最大線程池大小 executor.setMaxPoolSize(5); // 3.隊列大小 executor.setQueueCapacity(200); // 4.線程名稱 executor.setThreadNamePrefix("exchange-code-handler-"); // 5.拒絕策略 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; } }
在啟動類上添加注解
@EnableAsync
在想要異步執(zhí)行的方法上添加 @Async()注解
并指定ThreadPoolTaskExecutor 執(zhí)行器的名稱
@Override @Async("generateExchangeCodeExecutor") public void asyncGenerateCode(Coupon coupon) { ...... }
到此這篇關(guān)于SpringBoot中的異步執(zhí)行方法詳解的文章就介紹到這了,更多相關(guān)SpringBoot異步執(zhí)行內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java日期操作方法工具類實例【包含日期比較大小,相加減,判斷,驗證,獲取年份等】
這篇文章主要介紹了Java日期操作方法工具類,結(jié)合完整實例形式分析了java針對日期的各種常見操作,包括日期比較大小,相加減,判斷,驗證,獲取年份、天數(shù)、星期等,需要的朋友可以參考下2017-11-11關(guān)于JavaEE匿名內(nèi)部類和Lambda表達式的注意事項
這篇文章主要介紹了關(guān)于JavaEE匿名內(nèi)部類和Lambda表達式的注意事項,匿名內(nèi)部類顧名思義是沒有修飾符甚至沒有名稱的內(nèi)部類,使用匿名內(nèi)部類需要注意哪些地方,我們一起來看看吧2023-03-03springboot版本升級以及解決springsecurity漏洞的問題
這篇文章主要介紹了springboot版本升級以及解決springsecurity漏洞的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08java ReentrantLock條件鎖實現(xiàn)原理示例詳解
這篇文章主要為大家介紹了java ReentrantLock條件鎖實現(xiàn)原理示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-01-01java實現(xiàn)找出兩個文件中相同的單詞(兩種方法)
這篇文章主要介紹了java實現(xiàn)找出兩個文件中相同的單詞(兩種方法),需要的朋友可以參考下2020-08-08JDK動態(tài)代理之ProxyGenerator生成代理類的字節(jié)碼文件解析
這篇文章主要為大家詳細介紹了JDK動態(tài)代理之ProxyGenerator生成代理類的字節(jié)碼文件,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-02-02SpringBoot?Validation提示信息國際化配置方式
這篇文章主要介紹了SpringBoot?Validation提示信息國際化配置方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-02-02