1. 需求背景

  当我们需要提高系统的并发性能时,我们可以将耗时的操作异步执行,从而避免线程阻塞,提高系统的并发性能。例如,在处理大量的并发请求时,如果每个请求都是同步阻塞的方式处

理,系统的响应时间会变得很长。而使用异步编程,可以将一些耗时的操作交给其他线程去处理,从而释放主线程,提高系统的并发能力。

2. SpringBoot如何实现异步调用

  从Spring 3开始,可以通过在方法上标注@Async注解来实现异步方法调用。这意味着当我们调用被@Async注解修饰的方法时,它会在后台以异步方式执行。为了启用异步功能,我们需要

一个配置类,并在该类上使用@EnableAsync注解。这个注解告诉Spring要开启异步功能。

3. 异步调用实现步骤

第一步:新建配置类,开启@Async功能支持

  使用@EnableAsync来开启异步任务支持,@EnableAsync注解可以直接放在SpringBoot启动类上,也可以单独放在其他配置类上。这里选择使用单独的配置类SyncConfiguration

使用@Async注解,在默认情况下用的是SimpleAsyncTaskExecutor线程池,该线程池不是真正意义上的线程池

使用此线程池无法实现线程重用,每次调用都会新建一条线程。若系统中不断的创建线程,最终会导致系统占用内存过高,引发OutOfMemoryError错误,所以在使用Spring中的@Async异步

框架时要自定义线程池,替代默认的SimpleAsyncTaskExecutor,这也是自定义配置的意义之一。

@Configuration
@EnableAsync
public class SyncConfiguration {
@Bean(name = "asyncPoolTaskExecutor")
public ThreadPoolTaskExecutor executor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
//核心线程数,设置核心线程数。核心线程数是线程池中一直保持活动的线程数量,即使它们是空闲的。
taskExecutor.setCorePoolSize(10);
//设置线程池维护线程的最大数量。当缓冲队列已满并且核心线程数的线程都在忙碌时,线程池会创建新的线程,直到达到最大线程数。
taskExecutor.setMaxPoolSize(100);
//设置缓冲队列的容量。当所有的核心线程都在忙碌时,新的任务将会被放入缓冲队列中等待执行。
taskExecutor.setQueueCapacity(50);
//设置非核心线程的空闲时间。当超过核心线程数的线程在空闲时间达到设定值后,它们将被销毁,以减少资源的消耗。
taskExecutor.setKeepAliveSeconds(200);
//异步方法内部线程名称
taskExecutor.setThreadNamePrefix("async-");
/**
* 当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略
* 通常有以下四种策略:
* ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
* ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
* ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
* ThreadPoolExecutor.CallerRunsPolicy:重试添加当前的任务,自动重复调用 execute() 方法,直到成功
*/
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
taskExecutor.initialize();
return taskExecutor;
}
}

注:

Spring提供了多种线程池:

  • SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。

  • SyncTaskExecutor:这个类没有实现异步调用,只是一个同步操作。只适用于不需要多线程的地

  • ConcurrentTaskExecutor:Executor的适配类,不推荐使用。如果ThreadPoolTaskExecutor不满足要求时,才用考虑使用这个类

  • ThreadPoolTaskScheduler:可以使用cron表达式

  • ThreadPoolTaskExecutor :最常使用,推荐。 其实质是对java.util.concurrent.ThreadPoolExecutor的包装

第二步:在方法上标记异步调用

在异步处理的方法上添加@Async注解,代表该方法为异步处理。

public class AsyncTask {

    @Async
public void Task() {
long t1 = System.currentTimeMillis();
Thread.sleep(5000);
long t2 = System.currentTimeMillis();
log.info("task cost {} ms" , t2-t1);
}

第三步:在需要进行异步执行的地方进行调用

asyncTask.Task();

  

4. @Async的原理

  1. 当一个带有@Async注解的方法被调用时,Spring会创建一个异步代理对象来代理这个方法的调用。

  2. 异步代理对象会将方法调用封装为一个独立的任务,并将该任务提交给异步任务执行器。

  3. 异步任务执行器从线程池中获取一个空闲的线程,并将任务分配给该线程执行。

  4. 调用线程立即返回,不会等待异步任务的执行完成。

  5. 异步任务在独立的线程中执行,直到任务完成。

  6. 异步任务执行完成后,可以选择返回结果或者不返回任何结果。

 

SpringBoot 异步编程浅谈的更多相关文章

  1. 线程池+同步io和异步io(浅谈)

    线程池+同步io和异步io(浅谈) 来自于知乎大佬的一个评论 我们的系统代码从同步方式+线程池改成异步化之后压测发现性能提高了一倍,不再有大量的空闲线程,但是CPU的消耗太大,几乎打满,后来改成协程化 ...

  2. 新手也能看懂的 SpringBoot 异步编程指南

    本文已经收录自 springboot-guide : https://github.com/Snailclimb/springboot-guide (Spring Boot 核心知识点整理. 基于 S ...

  3. SpringBoot异步编程

    异步调用:当我们执行一个方法时,假如这个方法中有多个耗时的任务需要同时去做,而且又不着急等待这个结果时可以让客户端立即返回然后,后台慢慢去计算任务.当然你也可以选择等这些任务都执行完了,再返回给客户端 ...

  4. 多线程(NSThread、NSOperation、GCD)编程浅谈

    一.基本概念 进程:一个具有一定独立功能的程序关于某个数据集合的一次运行活动.可以理解成一个运行中的应用程序.线程:程序执行流的最小单元,线程是进程中的一个实体.同步:只能在当前线程按先后顺序依次执行 ...

  5. 白板编程浅谈——Why, What, How

    作者:Lucida 微博:@peng_gong 豆瓣:@figure9 原文链接:http://lucida.me/blog/whiteboard-coding-demystified/ 这篇文章节选 ...

  6. 白板编程浅谈——Why, What, How(转)

    原文链接:http://lucida.me/blog/whiteboard-coding-demystified/ 这篇文章节选自我正在撰写的一本关于应届生面试求职的书籍,欢迎在评论或微博(@peng ...

  7. Python核心编程 | 浅谈闭包的使用

    1.函数的引用   >>> def test(): print('test:') >>> test <function test at 0x10ffad488 ...

  8. Linux网络编程——浅谈 TCP 三次握手和四次挥手

    一.tcp协议格式 二.三次握手 在 TCP/IP 协议中.TCP 协议提供可靠的连接服务,採用三次握手建立一个连接. 第一次握手:建立连接时,client发送 syn 包(tcp协议中syn位置1. ...

  9. springboot异步线程(二)

    前言 本篇文章针对上篇文章springboot异步线程,有一位大佬在评论中提出第一点是错误的,当时看到了这个问题,最近刚好有空,针对第一点的问题去搜索了不少的文章: 问题 我在文章中第一点去验证:Sc ...

  10. springboot异步线程

    前言 最近项目中出现了一个问题,发现自己的定时器任务在线上没有执行,但是在线下测试时却能执行,最后谷歌到了这篇文章SpringBoot踩坑日记-定时任务不定时了?; 本篇文章主要以自己在项目中遇到的问 ...

随机推荐

  1. langchain中的LLM模型使用介绍

    简介 构建在大语言模型基础上的应用通常有两种,第一种叫做text completion,也就是一问一答的模式,输入是text,输出也是text.这种模型下应用并不会记忆之前的问题内容,每一个问题都是最 ...

  2. Jmeter MD5加密及其运用

    常用的几种加密方式 内置函数__MD5加密 参数说明: String to calculate MD5 hash(必填):要加密的字符串 Name of variable in which to st ...

  3. Vs2022安装.Net4.5程序包

    因为VS2022将不再支持.NET4.5,即使在Visual Studio Installer中也找不到.NET4.5的选项 我们可以在NuGet包中下载.NET 4.5的工具包 找到程序包管理器控制 ...

  4. nmcli 命令设置网络

    nmcli 命令设置网络 设置静态 IP 地址 sudo nmcli connection modify "连接名称" ipv4.addresses IP地址/子网掩码 设置网关 ...

  5. 常见python工具的基本构造-入门

    一.常见库 exifread 读取图片中的信息,如GPS信息 https://blog.csdn.net/qq1198768105/article/details/128159598 tkinter ...

  6. 记一次 Redisson 线上问题 → ERR unknown command 'WAIT' 的排查与分析

    开心一刻 昨晚和一个朋友聊天 我:处对象吗,咱俩试试? 朋友:我有对象 我:我不信,有对象不公开? 朋友:不好公开,我当的小三 问题背景 程序在生产环境稳定的跑着 直到有一天,公司执行组件漏洞扫描,有 ...

  7. ES 2023新特性速解

    ES 2023新特性速解 一.新增数组方法 操作数组的方法 Array.prototype.toSorted(compareFn) //返回一个新数组,其中元素按升序排序,而不改变原始数组. Arra ...

  8. 算法打卡|Day2 数组part02

    Day2 数组part02 今日任务:977.有序数组的平方 ,209.长度最小的子数组 ,59.螺旋矩阵II 目录 Day2 数组part02 今日任务:977.有序数组的平方 ,209.长度最小的 ...

  9. ElasticSearch系列——倒排索引、删除映射类型、打分机制、配置文件、常见错误

    文章目录 1 倒排索引 2 删除映射类型 一 前言 二 什么是映射类型? 三 为什么要删除映射类型? 四 映射类型的替代方法 4.1 将映射类型分开存储在索引中 4.2 自定义类型字段回到顶部 五 没 ...

  10. ubuntu实时查看网速

    可以使用ifstat这个命令 安装 apt install ifstat   1 使用,直接打命令就行 ifstat