SpringBoot 异步任务
Springboot异步任务
1、在编写之前,我们需要在Pom文件种添加 starter-web依赖组件,只有加入这个之后,才可以加入异步服务。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
2、需要在Springboot入口类也就是应用启动类加入 一个允许异类的注解,去表示当前应用需要使用异步任务
*@EnableScheduling //允许当前应用开启定时任务 * @EnableAsync //开启异步支持 * */ @EnableAsync //开启异步支持 @SpringBootApplication //表示当前是springboot应用 @EnableScheduling //允许当前应用开启定时任务 public class springapplicationstudy {
3、编写异步服务类
在处理异步服务的是时候,异步服务类需要被SpringBoot 扫描到,需要在异步类添加一个bean注解。@Service 或者Component
两者都是SpringBoot Bean 只不过@Component是基础类。
默认异步任务线程池配置,是不能重新利用线程池的,一个异步任务会起一个任务,这样会造成很大的一个资源浪费。
默认线程池的配置比较简单,一般情况需要定制优化一个线程池。
@Slf4j @Service public class AsyncService { @Async public void AsyncProcess() throws InterruptedException{ log.info("Async process Task Current thread name ---> {}", Thread.currentThread().getName());//获取当前线程池的名称 TimeUnit.SECONDS.sleep(2); //Jave 并发的一个插件。 } //有返回值 @Async public Future <Integer> AsyncProcessHasReturn() throws InterruptedException { log.info("Async Process [Has Return ],Get current thread name ----> {}", Thread.currentThread().getName()); TimeUnit.SECONDS.sleep(2); return new AsyncResult<>(100); } }
4、编写线程池配置类
编写自定义异步线程池,既然是配置那么配置注解肯定少不了了。
之程序的开始添加 @Configuration
首先申明一个线程池的对象,然后对线程池进行优化配置。
实现 AsyncConfigurer 重写 两个方法
getAsyncExecutor 线程池配置
-
setCorePoolSize //线程池核心数量
-
setMaxPoolSize //最大线程池数量,超过核心的进程以外的进程
-
setQueueCapacity //缓冲队列的个数
-
setKeepAliveSeconds // 超出的核心进程数量以外的进程存活时间
-
setThreadNamePrefix // 线程池前缀
-
setWaitForTasksToCompleteOnShutdown //是否等待所有线程执行完毕之后关闭线程池 默认false
-
setAwaitTerminationSeconds //等待时间
//拒绝策略
-
AbortPolicy() //当线程池满了,队列也满了,它会直接废弃并且报出异常
-
CallerRunsPolicy() //如果执行程序已经关闭了,则会丢弃这个任务
-
DiscardOldestPolicy() //当线程数量等于最大线程数量,队列是满的情况下,它就会抛弃线程池种最后一个,并执行新传递进来的任务
-
DiscardPolicy() //当线程数量等于或最大线程数量,不做任何的操作
//线程池初始化
initialize
getAsyncUncaughtExceptionHandler 进程异常处理
实现并且重写
AsyncUncaughtExceptionHandler 中的 handleUncaughtException 方法
package com.caicai.springboot.study.config; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.AsyncConfigurer; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.lang.reflect.Method; import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; /* * * 自定义异步线程池的配置 * * */ @Slf4j @Configuration //配置类注解 public class AsyncConfig implements AsyncConfigurer { //这里的Executor 是ThreadPool 它会返回一个线程池 //需要把这个注入到JavaBean @Bean @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10);//线程池核心数量 executor.setMaxPoolSize(20);//最大的线程池数量,也就超过核心池的时候,才会使用的 executor.setQueueCapacity(30);//缓冲队列的个数 executor.setKeepAliveSeconds(60);// 超出核心进程数量之外的线程数量的最大存活时间。默认60秒,超过则会被杀掉 executor.setThreadNamePrefix("Caicai_Async_");//线程名的前缀 executor.setWaitForTasksToCompleteOnShutdown(true);//是否等待所有线程执行完毕之后关闭线程池 executor.setAwaitTerminationSeconds(60); // 等待的时间,默认是0.也就是setWaitForTasksToCompleteOnShutdown 这个的等待时间 //拒绝策略 //用与被拒绝处理的一个处理程序,它直接在executor 的方法的调用线程中运行被拒绝的任务 executor.setRejectedExecutionHandler( new ThreadPoolExecutor.AbortPolicy() //AbortPolicy() 当线程池满了,队列也满了,它会直接废弃并且报出异常 //CallerRunsPolicy() //如果执行程序已经关闭了,则会丢弃这个任务 //DiscardOldestPolicy() 当线程数量等于最大线程数量,队列是满的情况下,它就会抛弃线程池种最后一个,并执行新传递进来的任务 //DiscardPolicy() 当线程数量等于或最大线程数量,不做任何的操作 ); //线程初始化 executor.initialize(); return executor; } // getAsyncUncaughtExceptionHandler 定义异常处理 /* * 定义异步任务异常处理类,只会处理没有返回结果异步任务,有返回结果的任务会 * 交给客户端 * * */ @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return new AsyncExceptionHandler(); } static class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler{ @Override public void handleUncaughtException(Throwable throwable, Method method, Object... objects) { log.info("AsyncError:{} ,Method:{},Param:{}",throwable.getMessage(),method.getName(), JSON.toJSONString(objects));//返回值,以json的形式返回 throwable.printStackTrace();//打印 //TODO 发送邮件或者手机短信 } } }
5、在异步服务类的异步注解添加指定线程池名称
@Async("getAsyncExecutor")//指定使用线程池名称
开开心心,上班!
快快乐乐,游玩!
及时行乐!