@Async之SpringBoot异步处理进阶方式

@Async之SpringBoot异步处理

为了提高接口的返回速度,常用的手段是热数据的缓存和异步处理请求。如一个接口需要查询多个表的数据做处理,需要对查询结果缓存起来,以便提高后面的请求反应速度时,可以通过一个异步处理来把结果缓存起来,这样既不耽误第一个请求的返回速度,也能提高后面请求的返回速度。

使用步骤
1. 把异步处理的业务代码放在一个独立的方法内部,在方法上面贴上@Async注解。
@Async
    public void getDateFromDataBase(Object date) {
		/**
			注意:在做了缓存的查询了,必须要先查询缓存中是否存有对应的数据,如果
			没有再接着走查询数据库的流程。
		/
    }
2. 在主配置类添加@EnableAsync注解,开启异步处理功能。
@SpringBootApplication
@EnableAsync
public class MianApplication{

    public static void main(String[] args) {
        SpringApplication.run(MianApplication.class, args);
    }

}
3. 注意

以上方法是最简单的实现异步处理途径,当系统的请求不多时,可以直接使用。但是这种方法存在一个问题。首先我们需要知道,之所以SpringBoot可以异步执行这些方法,其原理是使用了多线程。SpringBoot会在需要执行这些方法的时候开启一个新的线程去执行异步方法。以上面的代码为例,这里的问题就是,如果同一时间有很多的请求同时访问这个方法,因为在所有请求在进入方法时,异步方法还没有执行完毕,所以所有请求在检查缓存时,都不可能会查到缓存的数据,此时就会有很多的请求同时进入异步方法,而执行异步方法就需要新建一个线程,如果安装上面的处理逻辑,有多少个请求执行异步方法,就会新建多少个线程,这样就有可能会出现新建的线程过多,导致OOM异常。
如果需要限制创建线程的数量,可以使用线程池来限制创建线程的数量。

使用线程池方式改进异步处理
1. 创建线程池

在创建线程池时,一般我们不会直接使用线程池提供的工具类,而是使用ThreadPoolTaskExecutor。我们可以在创建线程池时根据系统的需求,创建出适量的核心线程数、最大线程数等。

@EnableAsync
@Configuration
public class TaskPoolConfig {

	/**
		核心线程数
	/
    @Value("${task.poolSize}")
    private Integer poolSize;

	/**
		最大线程数
	/
    @Value("${task.maxPoolSize}")
    private Integer maxPoolSize;

	/**
		线程等待队列
	/
    @Value("${task.queueCapacity}")
    private Integer queueCapacity;

	/**
		线程存活时间
	/
    @Value("${task.aliveTime}")
    private Integer aliveTime;

    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(poolSize);
        threadPoolTaskExecutor.setKeepAliveSeconds(aliveTime);
        threadPoolTaskExecutor.setQueueCapacity(queueCapacity);
        threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize);
        threadPoolTaskExecutor.setThreadNamePrefix("taskExecutor-");
        threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return threadPoolTaskExecutor;
    }
}
2. 在异步处理时,使用我们自定义的线程池
@Component
public class MyAsyncTask {
    private static final DateTimeFormatter DATE_TIME_FORMATTER = 
    DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Async("taskExecutor")
    public void doTask(String aa) throws InterruptedException {
        System.out.println("开始执行任务: " + aa + ", 时间为: " 
        + DATE_TIME_FORMATTER);
        Thread.sleep(20000);
        System.out.println("执行任务完毕: " + aa + "时间为: " 
        + DATE_TIME_FORMATTER);
    }
}
注意

此处需要使用到我们自定义的线程池,所以我们必须要把当前类交给Spring管理,因为只有Spring容器中的bean才能使用Spring提供的内容,所以如果出现无法注入自定义的异步方法时,需要检查bean是否已经交给Spring管理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值