前言
首先我们来看看在Spring中为什么要使用异步编程,它能解决什么问题?
什么是异步?
首先我们先来看看一个同步
的用户注册例子,流程如下:
异步
的方式如下:
在用户注册后将成功结果返回,使用异步的方式来赠送优惠券,接下来我们来看一下代码示例。
示例
第一步:新建配置类,开启@Async功能支持
使用@EnableAsync
来开启异步任务支持,@EnableAsync
注解可以直接放在SpringBoot启动类
上,也可以单独放在其他配置类上。我们这里选择使用单独的配置类SyncConfiguration
新建配置类AsyncConfiguration
@Configuration
@EnableAsync
public class AsyncConfiguration {
}
第二步:在方法上标记异步调用
增加一个Component类,用来进行业务处理,同时添加@Async注解,代表该方法为异步处理。
@Component
public class MemberServiceAsync {
private static Logger logger = Logger.getLogger(MemberServiceAsync.class);
@Async
public void sendCoupons() {
try {
logger.info("发送优惠券");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
第三步:在Controller中进行异步方法调用
@RestController
public class MemberService {
private static Logger logger = Logger.getLogger(MemberService.class);
@Resource
private MemberServiceAsync async;
@RequestMapping("insertMember")
public String insertMember() {
logger.info("会员新增数据");
async.sendCoupons();
return "注册成功";
}
}
访问该接口并查看控制台信息
[INFO ] 2023-03-09 19:52:04,433 method:com.mayikt.service.MemberService.insertMember(MemberService.java:19)
会员新增数据
[INFO ] 2023-03-09 19:52:04,439 method:com.mayikt.service.MemberService.insertMember(MemberService.java:21)
注册成功
[INFO ] 2023-03-09 19:52:04,446 method:com.mayikt.service.MemberServiceAsync.sendCoupons(MemberServiceAsync.java:25)
发送优惠券
通过日志可以看到:主线程不需要等待异步方法执行完成,减少了响应时间,提高了接口性能。
通过上面三步我们就可以在SpringBoot中欢乐的使用异步方法来提高我们接口性能了
线程池
为异步操作提供一个线程池,我们在配置类中加上代码
@Configuration
@EnableAsync
public class AsyncConfiguration {
@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;
}
}
在注解上指定bean的名称:@Async(“asyncPoolTaskExecutor”)就可以了