SpringBoot异步执行方法

news2024/11/16 19:33:48

1. 源码跟踪

1.简单描述

在SpringBoot2.0.9之前需要手动自定义线程池(如下2.1), 然后指定线程池的名称

SpringBoot2.0.9以及之前的版本,使用的线程池默认是SimpleAsyncTaskExcutor, , 之后的版本使用的是ThreadpoolTaskExecutor

并且不需要手动的创建当前线程池(但往往我们还是会手动指定,具体原因看源码就可以自有判断⚜️ ).

SpringBoot会自动的扫描两个文件下的配置信息:

所以如果我们写的配置类想让SpringBoot自动扫描到就可以放到两个中的任意一个

我们项目中就是这样使用的:在 spring.factories文件中指定一些配置类相对路径,这样配置类中的指定的Bean就可以放入到IOC容器中了

SpringBoot在org.springframework.boot.autoconfigure.AutoConfiguration.imports118行配置了TaskExecutionAutoConfiguration的位置,这样SpringBoot就可以扫描到当前配置类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sOUosu98-1685781636628)(C:\Users\57589\AppData\Roaming\Typora\typora-user-images\image-20230603155549533.png)]

2. TaskExecutionAutoConfiguration

配置类信息如下

@ConditionalOnClass({ThreadPoolTaskExecutor.class})   // 代表如果容器中有这个类,就不在创建
@AutoConfiguration
@EnableConfigurationProperties({TaskExecutionProperties.class})  // 配置文件
public class TaskExecutionAutoConfiguration {
    // 应用程序任务执行器任务名称 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();
    }
3. TaskExecutionProperties

配置文件中

定义了线程名 task -

4. 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;
	
	//       ......  ......................省略
	// 创建代码
	@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("默认核心线程数:"+executor.getCorePoolSize());
    System.out.println("默认最大线程数:"+executor.getMaxPoolSize());
    System.out.println("当前活跃线程数:"+executor.getActiveCount());
    System.out.println("临时线程空闲时间:"+executor.getKeepAliveSeconds());
    System.out.println("队列最大值:"+executor.getQueueCapacity());
    System.out.println("队列数量:"+executor.getQueueSize());
}

结果如下:

org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor@7410c197
默认前缀:task-
默认核心线程数:8
默认最大线程数:2147483647
当前活跃线程数:0
临时线程空闲时间:60
队列最大值:2147483647
队列数量:0

我们可以看到SpringBoot中默认配置的线程池的数量, 很不符合我们的实际要求, 而且还容易发生OOM(Out Of Memory)

所以我们一般是手动指定线程池中的信息

2. SpringBoot异步执行方法

1.定义一个配置类

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;
    }
}
2. 在启动类上添加注解
@EnableAsync
3. 在想要异步执行的方法上添加 @Async()注解

并指定ThreadPoolTaskExecutor 执行器的名称

    @Override
    @Async("generateExchangeCodeExecutor")
    public void asyncGenerateCode(Coupon coupon) {
    		......
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/605142.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多线程基础(五)ThreadLocal与四种引用

一、ThreadLocal ThreadLocal&#xff1a;解决每个线程绑定自己的值&#xff0c;存放线程的私有数据。 public class ThreadLocalTest {public static ThreadLocal local new ThreadLocal();public static void main(String[] args) {if(local.get() null){local.set("…

加成序列 dfs 迭代加深 java

&#x1f351; 加成序列 满足如下条件的序列 X X X&#xff08;序列中元素被标号为 1 、 2 、 3 … m 1、2、3…m 1、2、3…m&#xff09;被称为“加成序列”&#xff1a; KaTeX parse error: Undefined control sequence: \[ at position 2: X\̲[̲1\]1KaTeX parse error…

一文读懂MVCC:数据库中的并发读写利器!

大家好&#xff0c;我是你们的小米&#xff0c;一个积极活泼、喜好分享技术的小伙伴。今天&#xff0c;我想和大家聊一聊数据库领域的一个重要话题——MVCC多版本并发控制。MVCC是MySQL和其他一些数据库系统中常用的并发控制技术&#xff0c;通过它&#xff0c;我们可以在高并发…

如何用 Python 实现所有算法?

学会了 Python 基础知识&#xff0c;想进阶一下&#xff0c;那就来点算法吧&#xff01;毕竟编程语言只是工具&#xff0c;结构算法才是灵魂。 新手如何入门 Python 算法&#xff1f; 几位印度小哥在 GitHub 上建了一个各种 Python 算法的新手入门大全。从原理到代码&#xff0…

milkV-duo的Linux的开发环境搭建

目录 写在前面 内核编译 烧录失败的示例&#xff08;这种情况下就和插上空卡一样) 进入系统 串口进入 SSH接入 写在前面 基本上大部分的问题都能在开源社区上得到答案,记录下我遇到的问题. 附上开源社区 MilkV Community 这里的引脚图和板子的丝印有点对不上&#xff…

竞赛中常用的Python 标准库

对竞赛中常用得标准库进行解析和给出代码模板 目录 1.functools 1.1 cmp_to_key 1.2 lru_cache&#xff08;记忆化存储&#xff0c;加快递归速度&#xff09; 2.collections 2.1 deque 2.1.1 单调对列实现 2.1.2 BFS广搜 3.sys 3.1 sys.maxsize 3.2 sys.exit() 3.…

使用python的plot绘制loss、acc曲线,并存储成图片

使用 python的plot 绘制网络训练过程中的的 loss 曲线以及准确率变化曲线&#xff0c;这里的主要思想就时先把想要的损失值以及准确率值保存下来&#xff0c;保存到 .txt 文件中&#xff0c;待网络训练结束&#xff0c;我们再拿这存储的数据绘制各种曲线。 其大致步骤为&#x…

代码自动生成工具——TableGo(实例演示)

一、常用的代码生成器工具介绍 在SpringBoot项目开发中&#xff0c;为了提高开发效率&#xff0c;我们经常需要使用代码自动生成工具来生成一些重复性的代码&#xff0c;比如实体类、DAO、Service、Controller等等。下面介绍几个常用的代码自动生成工具&#xff1a; ①、MyBat…

如何在Linux 启用组播

第一章: 前言 多播技术&#xff0c;也被称为“组播”&#xff0c;是一种网络通信机制&#xff0c;它允许一个节点&#xff08;发送者&#xff09;向一组特定的节点&#xff08;接收者&#xff09;发送信息。这种方式在网络编程中非常有用&#xff0c;因为它可以大大提高效率和…

深度学习(Pytorch):Softmax回归

Softmax简介 Softmax回归是一个用于多类分类问题的线性模型&#xff0c;它是从Logistic回归模型演变而来的。Softmax回归与Logistic回归类似&#xff0c;但是输出不再是二元的&#xff0c;而是多类的。Softmax回归引入了softmax激活函数来将输出转换为合理的概率分布。与线性回…

HCIE-Cloud Computing LAB备考--第五题:规划--Type13练习--记忆技巧+默写

对LLD表,交换机接口表,ensp配置进行练习,如下图,设置答案和空白表,进行默写,汇总自己的容易犯的错误 LLD表默写思路 交换机接口配置表默写思路 以Type3为例,同颜色复制即可,共用ST.P0是A25,ST.P2是A21,FS是ST.P0是A21,ST.P2是A21。 ensp配置默写思路 特点: 所…

一步一步学习 Stable Diffusion

一步一步学习 Stable Diffusion 0. 背景1. 安装2. 汉化3. 安装 sd-webui-controlnet 插件4. 安装 sd-webui-segment-anything 插件5. 安装 ultimate-upscale 插件6. 安装 SadTalker 插件7. 下载和配置 VAE 模型8. 使用 ChilloutMix 模型99. 未完待续 0. 背景 网上看了很多 Sta…

priority_queue(优先级队列)

priority_queue 1. priority_queue的介绍及使用1.1 priority_queue的介绍1.2 priority_queue的使用1.2.1 constructor(构造)1.2.2 empty1.2.3 size1.2.4 top1.2.5 emplace1.2.6 push、pop、swap 1.3 数组中第K个大的元素 2.priority_queue的深度剖析及模拟实现 1. priority_que…

Makerbase SimpleFOC ESP32例程4 双电机闭环速度测试

Makerbase SimpleFOC ESP32例程4 双电机闭环速度测试 第一部分 硬件介绍 1.1 硬件清单 序号品名数量1ESP32 FOC V1.0 主板12YT2804电机2312V电源适配器14USB 线156pin杜邦线2 注意&#xff1a;YT2804是改装的云台无刷电机,带有AS5600编码器&#xff0c;可实现360连续运转。…

柔性作业车间调度

1柔性车间作业调度 个工件 要在 台机器 上加工。每个工件包含一道或多道工序&#xff0c;工序顺序是预先确定的&#xff0c;每道工序可以在多台不同加工机器上进行加工&#xff0c;工序的加工时间随加工机器的不同而不同。调度目标是为每道工序选择最合适的机器、确定每台机器…

【C语言】语言篇——数组和字符串

C站的小伙伴们&#xff0c;大家好呀&#x1f61d;&#x1f61d;&#xff01;我最近在阅读学习刘汝佳老师的《算法竞赛入门经典》&#xff0c;今天将整理本书的第三章——数组和字符串的一些习题&#xff0c;本章习题较多&#xff0c;下选取部分习题进行练习总结&#xff0c;在这…

200道面试题(附答案)

最近有不少小伙伴跑来咨询&#xff1a; 想找网络安全工作&#xff0c;应该要怎么进行技术面试准备&#xff1f;工作不到 2 年&#xff0c;想跳槽看下机会&#xff0c;有没有相关的面试题呢&#xff1f; 为了更好地帮助大家高薪就业&#xff0c;今天就给大家分享两份网络安全工…

ubuntu20.04 ffmpeg mp4转AES加密的m3u8分片视频

样本视频(时长2分35秒): 大雄兔_百度百科 大雄兔_百度百科不知大家否看过世界上第一部开源电影&#xff1a;Elephants Dream&#xff08;大象之梦&#xff09;。这是一部由主要由开源软件Blender制作的电影短片&#xff0c;证明了用开源软件也能制作出效果媲美大公司的作品。…

1-9 随机算法【手写+Xmind笔记】

文章目录 1 Min-Cut【手写笔记】1.1 问题描述1.2 解决方案1.3 概率证明 2 赠券收集【手写笔记】3 快排期望【手写笔记】4 素数性质【手写笔记】4.1 基本性质4.2 解决方案4.3 群论4.4 费马小定理4.5 Miller Rabin素性测试 5-6 力矩与偏差【手写笔记】5.1 基础不等式5.2 矩生成函…

[图表]pyecharts模块-柱状图

[图表]pyecharts模块-柱状图 先来看代码&#xff1a; from pyecharts.charts import Bar from pyecharts.faker import Faker from pyecharts.globals import ThemeTypec (Bar({"theme": ThemeType.MACARONS}).add_xaxis(Faker.choose()).add_yaxis("商家A&q…