SpringBoot异步使用@Async原理及线程池配置
前言
在实际项目开发中很多业务场景需要使用异步去完成,比如消息通知,日志记录,等非常常用的都可以通过异步去执行,提高效率,那么在Spring框架中应该如何去使用异步呢
使用步骤
完成异步操作一般有两种,
消息队列MQ,和线程池处理ThreadPoolExecutor
而在Spring4中提供的对ThreadPoolExecutor封装的线程池ThreadPoolTaskExecutor,直接使用注解启用@Async,这个注解让我们在使用Spring完成异步操作变得非常方便
配置线程池类参数配置
自定义常量类
public class ConstantFiledUtil {
public static final String AUTHORIZATION_TOKEN = "authorizationToken";
/**
* kmall线程池名称
*/
public static final String KMALL_THREAD_POOL = "KmallThreadPool";
/**
* kmall线程名称前缀
*/
public static final String KMALL_THREAD_NAME_PREFIX = "kmall-thread-";
}
配置线程池
@Configuration(proxyBeanMethods = false)
@EnableAsync //开启注解
public class KmallConfig {
@Bean(ConstantFiledUtil.KMALL_THREAD_POOL)
public ThreadPoolTaskExecutor FebsShiroThreadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(5);
//配置最大线程数
executor.setMaxPoolSize(20);
//配置队列大小
executor.setQueueCapacity(200);
//线程池维护线程所允许的空闲时间
executor.setKeepAliveSeconds(30);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix(ConstantFiledUtil.KMALL_THREAD_NAME_PREFIX);
//设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean
executor.setWaitForTasksToCompleteOnShutdown(true);
//设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住
executor.setAwaitTerminationSeconds(60);
// rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
}
注意这里需要通过
@EnableAsync开启异步否则无效
自定义线程任务
public interface ILogService extends IService<Log> {
/**
* 分页搜索查询日志信息
* @param logParams
* @return
*/
IPage getSearchLogByPage(SearchLogParams logParams);
/**
* 保存日志
*
* @param logSubject
*/
@Async
void saveLog(LogSubject logSubject);
}
在需要异步执行的接口,或者方法上加上@Async注解此方法就是异步方法,在主程序中调用的化,就是异步方式单独线程执行
此注解表明saveLog方法进入的线程池是KmallThreadPool方法创建的。
我们也可以单独指定方法名称@Async("saveLogs")
这样在进行日记记录的时候就是单独线程执行每次请求都快速响应了,而耗时的操作都留给线程池中的线程去异步执行
总结
Spring中用@Async注解标记的方法,称为异步方法。在spring boot应用中使用@Async很简单:
- 调用异步方法类上或者启动类加上注解@EnableAsync
- 在需要被异步调用的方法外加上@Async
- 所使用的@Async注解方法的类对象应该是Spring容器管理的bean对象;
注意同一个类里面调用异步方法不生效:原因默认类内的方法调用不会被
aop拦截,即调用方和被调用方是在同一个类中,是无法产生切面的,该对象没有被Spring容器管理。即@Async方法不生效
解决办法:
如果要使同一个类中的方法之间调用也被拦截,需要使用spring容器中的实例对象,而不是使用默认的this,因为通过bean实例的调用才会被spring的aop拦截
本例使用方法:AsyncService asyncService = context.getBean(AsyncService.class); 然后使用这个引用调用本地的方法即可达到被拦截的目的
备注:这种方法只能拦截protected,default,public方法,private方法无法拦截。这个是spring aop的一个机制。
原理刨析
异步方法返回类型只能有两种:
当返回类型为void的时候,方法调用过程产生的异常不会抛到调用者层面,可以通过注
AsyncUncaughtExceptionHandler来捕获此类异常当返回类型为Future的时候,方法调用过程产生的异常会抛到调用者层面
注意如果不自定义异步方法的线程池默认使用
SimpleAsyncTaskExecutor。SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。并发大的时候会产生严重的性能问题。
Spring异步线程池接口 TaskExecutor
看源码可知
@FunctionalInterface
public interface TaskExecutor extends Executor {
void execute(Runnable var1);
}
它的实先类有很多如下:

SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。SyncTaskExecutor:这个类没有实现异步调用,只是一个同步操作。只适用于不需要多线程的地方ConcurrentTaskExecutor:Executor的适配类,不推荐使用。如果ThreadPoolTaskExecutor不满足要求时,才用考虑使用这个类
SimpleThreadPoolTaskExecutor:是Quartz的SimpleThreadPool的类。线程池同时被quartz和非quartz使用,才需要使用此类ThreadPoolTaskExecutor :最常使用,推荐。 其实质是对java.util.concurrent.ThreadPoolExecutor的包装,
————————————————
文章参考
- Spring Boot(5) @Async异步线程池详解
- https://segmentfault.com/a/1190000040134160?utm_source=sf-similar-article
SpringBoot异步使用@Async原理及线程池配置的更多相关文章
- SpringBoot异步及线程池配置
异步方法注解@Async 在SpringBoot中进行异步处理,可以使用异步注解@Async和@EnableAsync. @Async注解表示异步,如:@Async("asyncServic ...
- Spring线程池配置模板设计(基于Springboot)
目录 线程池配置模板 基础的注解解释 常用配置参数 配置类设计 线程池使用 ThreadPoolTaskExecutor源码 线程池配置模板 springboot给我们提供了一个线程池的实现,它的底层 ...
- SpringBoot 线程池配置 实现AsyncConfigurer接口方法
目的是: 通过实现AsyncConfigurer自定义线程池,包含异常处理 实现AsyncConfigurer接口对异常线程池更加细粒度的控制 *a) 创建线程自己的线程池 b) 对void ...
- 玩转SpringBoot之定时任务@Scheduled线程池配置
序言 对于定时任务,在SpringBoot中只需要使用@Scheduled 这个注解就能够满足需求,它的出现也给我们带了很大的方便,我们只要加上该注解,并且根据需求设置好就可以使用定时任务了. 但是, ...
- SpringBoot学习笔记(七):SpringBoot使用AOP统一处理请求日志、SpringBoot定时任务@Scheduled、SpringBoot异步调用Async、自定义参数
SpringBoot使用AOP统一处理请求日志 这里就提到了我们Spring当中的AOP,也就是面向切面编程,今天我们使用AOP去对我们的所有请求进行一个统一处理.首先在pom.xml中引入我们需要的 ...
- Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就绪,挂起,运行) ,***协程概念,yield模拟并发(有缺陷),Greenlet模块(手动切换),Gevent(协程并发)
Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就 ...
- 【Java 并发】Executor框架机制与线程池配置使用
[Java 并发]Executor框架机制与线程池配置使用 一,Executor框架Executor框架便是Java 5中引入的,其内部使用了线程池机制,在java.util.cocurrent 包下 ...
- TestNg线程池配置、执行次数配置、超时配置
使用注解的方式对TestNg线程池配置.执行次数配置.超时配置 注:使用注解来控制测试方法运行的次数和超时时间,timeOut在单线程或者多线程模式下都可用,threadPoolSize设置了线程池的 ...
- TestNG的參数化測试、共享线程池配置、參数默认值配置
在使用TestNG进行測试时,常常会使用到一些參数化配置,比方数据库.连接池.线程池数. 使用TestNG的參数@Parameter注解进行自己主动化读取 原创文章,版权全部.同意转载,标明出处:ht ...
随机推荐
- CentOS 8.0 安装docker 报错:Problem: package docker-ce-3:19.03.4-3.el7.x86_64 requires containerd.io >= 1
1.错误内容 package docker-ce-3:19.03.2-3.el7.x86_64 requires containerd.io >= 1.2.2-3, but none of th ...
- Flutter学习(8)——CheckBox多选框使用及动态更改多选框数据
原文地址:Flutter学习(8)--CheckBox多选框使用及动态更改多选框数据 | Stars-One的杂货小窝 最近项目需求需要调整页面,记录一下实现过程 这次主要是要实现个评价页面,选择不同 ...
- Commons-Beanutils利用链分析
前言 本篇开始介绍 commons-beanutils 利用链,注意Commons-Beanutils 不是Commons-Collections 不要看混了,首先来看一下,什么是 commons-b ...
- Java自定义注解使用和详解
前言 我们在做开发springboot 项目时候会遇到各种各样注解,使用各种各样注解,极大的简便了我们开发流程,方式,从JDK5开始支持 注解是Java语言的一种强大的功能 可以理解为代码上的特殊标记 ...
- 常见的嵌入式linux学习和如何选择ARM芯片问答
常见的ARM嵌入式学习问答,设计者和学习者最关心的11个问题: 1. ARM嵌入式是学习硬件好还是学习软件好? 2. 嵌入式软件和硬件,哪一种职位待遇更高?或者说, ...
- Mysql数据库优化(1)
1.尽量不要留null select id from t where num is null,可以,但尽量不要留null,null也占空间:使用not null填充数据库,像varchar(100)这 ...
- iOS开发之蜂窝布局—Swift
前言 最近项目中用到了类似蜂窝的六边形布局,在这里分享出来抛砖引玉,供大家参考学习.本文提供了2种思路实现效果,第一种方式使用UICollectionView实现,第二种方式使用UIScrollVie ...
- CAS 5.3服务器搭建
一.本例环境说明 JDK 1.8 CAS 5.3 apache-maven-3.6.0 二.CAS安装步骤 2.1 提前安装好JDK和Maven环境 安装步骤略 2.2 CAS环境搭建 2.2.1 C ...
- 「移动端」Web页面适配
一.什么是移动端适配 移动端 Web 页面,就是常说的手机 h5页面.webview页面.公众号开发的网页等. 由于手机机型较多,各个手机的屏幕尺寸不一样,所以做移动端页面,需要考虑在安卓和ios的各 ...
- FirstGradle
一.导入依赖 二.build.gradle 整合SpringBoot plugins { id 'java' } group 'com.qiang' version '1.0.0-SNAPSHOT' ...