在SpringBoot中提供了异步任务的功能特性。
1.引入spring-boot-starter-web依赖
2.在Application启动类上标注@EnableAsync注解
3.编写异步方法:
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
/**
* 异步处理服务
*/
@Slf4j
@Service
public class AsyncService {
@Async("getAsyncExecutor")
public void asyncProcess() throws InterruptedException {
log.info("async process task, current thread name -> {}",
Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(2);
}
@Async("getAsyncExecutor")
public Future<Integer> asyncProcessHasReturn() throws InterruptedException {
log.info("async process task (has return), current thread name -> {}",
Thread.currentThread().getName());
TimeUnit.SECONDS.sleep(2);
return new AsyncResult<>(100);
}
}
此异步任务服务中定义了一个无返回值的异步方法,一个有返回值的方法。异步任务方法上须标注@Async注解,通过@Async指定使用的异步线程池。
4.自定义异步线程池
默认情况下,springboot异步线程池特别简单,使得线程不能被重新利用。每次调用方法时都会重新创建线程。
因此需要对异步线程池做自定义配置:
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
/**
* <h1>自定义异步线程池的配置</h1>
*/
@Slf4j
@Configuration
public class AsyncPoolConfig implements AsyncConfigurer {
}
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;
/**
* <h1>自定义异步线程池的配置</h1>
* 使用@Configuration标注配置类
* 须继承AsyncConfigurer接口
*/
@Slf4j
@Configuration
public class AsyncPoolConfig implements AsyncConfigurer {
/**
* 获取自定义的ThreadPoolExcutor
* 使用@Bean将其注入spring容器中
* */
@Bean
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);//线程池核心线程的数量
executor.setMaxPoolSize(20);//线程池维护线程的最大数量
executor.setQueueCapacity(20);//缓冲队列任务的个数
executor.setKeepAliveSeconds(60);//超出核心线程数的线程最大存活时间
executor.setThreadNamePrefix("ImoocAsync_");
executor.setWaitForTasksToCompleteOnShutdown(true);//是否等待所有线程执行完毕后才关闭线程池
executor.setAwaitTerminationSeconds(60);//要关闭的等待时长,与上句一起生效
// 拒绝策略
executor.setRejectedExecutionHandler(
new ThreadPoolExecutor.AbortPolicy()
);
executor.initialize();
return executor;
}
/**
* <h2>定义异步任务异常处理类</h2>
* 返回自定义的AsyncExceptionHandler对象用作异常处理器
* */
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncExceptionHandler();
}
/**
* 自定义异常处理器 包含异常处理逻辑
*/
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));
throwable.printStackTrace();
// TODO 发送邮件或者短信
}
}
}