首先说下我这边的业务场景,在接收mqtt消息时,消息会有很多,开启异步线程,相当于你需要消费大量的消息的时候不需要考虑其顺序性,一般是自己定义线程池,用多线程的方式去消费,但是如果你的模块中有多个方法需要使用多线程,你就需要定义多次。
从我自己的理解分为两个概念来解释
1.异步
主要用到的是@EnableAsync和@Async
@EnableAsync
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AsyncConfigurationSelector.class})
public @interface EnableAsync {
Class<? extends Annotation> annotation() default Annotation.class;
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default 2147483647;
}
@EnableAsync
只能标注在类上,表示开启异步执行,通常加在启动类上
@Async
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Async {
String value() default "";
}
@Async
可以标注在类上、方法上。标注在类上时,此类的所有方法都将异步执行,标注在类上时,只有此方法异步执行。且此注解标注的方法不能有返回值,否则执行时将报错。
默认使用的线程池是Spring Boot
提供的SimpleAsyncTaskExecutor
@Async失效的情况
- 异步方法使用static修饰
- 异步类实例没有交给Spring管理(即没有用@Component等注解修饰)
- 异步方法的调用和异步方法在同一个类中
- 没有使用@EnableAsync注解开启异步执行
- @Async修饰的方法有返回值(执行时出错)
2.异步线程池
创建线程池配置类(可以放在特定的服务中,创建特定的线程池)
@Configuration
@Slf4j
public class ExecutorConfig {
@Value("${async.executor.thread.core_pool_size}")
private int corePoolSize;
@Value("${async.executor.thread.max_pool_size}")
private int maxPoolSize;
@Value("${async.executor.thread.queue_capacity}")
private int queueCapacity;
@Value("${async.executor.thread.name.prefix}")
private String namePrefix;
@Value("${async.executor.thread.keep_alive_seconds}")
private int keepAliveSeconds;
@Bean(name = "asyncTaskExecutor")
//ThreadPoolTaskExecutor实现了AsyncListenableTaskExecutor,AsyncListenableTaskExecutor继承了AsyncTaskExecutor
public ThreadPoolTaskExecutor taskExecutor() {
log.info("启动");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心线程数
executor.setCorePoolSize(corePoolSize);
// 最大线程数
executor.setMaxPoolSize(maxPoolSize);
// 任务队列大小
executor.setQueueCapacity(queueCapacity);
// 线程前缀名
executor.setThreadNamePrefix(namePrefix);
// 线程的空闲时间
executor.setKeepAliveSeconds(keepAliveSeconds);
// 拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 线程初始化
executor.initialize();
return executor;
}
}
异步线程池的配置(可以放在公共包中,去创建默认的线程池)
因为加了ConditionalOnMissingBean注解,如果特定服务有特定线程池的话,不会再创建一个AsyncTaskExecutor的bean对象了
@Configuration
@EnableAsync
public class AsyncTaskExecutorConfiguration implements AsyncConfigurer {
private static final Logger logger = LoggerFactory.getLogger(AsyncTaskExecutorConfiguration.class);
@Resource
private ScCloudProperties scCloudProperties;
@Resource
private AsyncTaskExecutor asyncTaskExecutor;
@Bean
@ConditionalOnMissingBean(AsyncTaskExecutor.class)
//@ConditionalOnMissingBean注解的作用是相同的bean只注入一个,如果存在AsyncTaskExecutor的Bean就不再创建了
public AsyncTaskExecutor asyncTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(scCloudProperties.getTask().getCorePoolSize());
executor.setMaxPoolSize(scCloudProperties.getTask().getMaxPoolSize());
executor.setKeepAliveSeconds(scCloudProperties.getTask().getKeepAliveSeconds());
executor.setQueueCapacity(scCloudProperties.getTask().getQueueCapacity());
executor.setThreadNamePrefix(scCloudProperties.getTask().getThreadNamePrefix());
return executor;
}
@Override
@Bean(name = "taskExecutor")
public Executor getAsyncExecutor() {
logger.debug("Creating Async Task Executor");
return new ScAsyncTaskExecutor(asyncTaskExecutor);
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
线程池配置参数的类:(如果前面步骤中已经配置好了线程池这边参数实际上是不需要的)
@ConfigurationProperties(prefix = "sc.cloud")
public class ScCloudProperties {
private boolean dev;
private AsyncTaskProperties task = new AsyncTaskProperties();
private SwaggerProperties swagger = new SwaggerProperties();
public boolean getDev() {
return dev;
}
public void setDev(boolean dev) {
this.dev = dev;
}
public AsyncTaskProperties getTask() {
return task;
}
public void setTask(AsyncTaskProperties task) {
this.task = task;
}
public SwaggerProperties getSwagger() {
return swagger;
}
public void setSwagger(SwaggerProperties swagger) {
this.swagger = swagger;
}
}
application.yml文件中的配置:
# 异步线程配置
# 核心线程数
async:
executor:
thread.core_pool_size: 20
# 最大线程数
thread.max_pool_size: 50
# 任务队列大小
thread.queue_capacity: 200
# 线程池中线程的名称前缀
thread.name.prefix: async-service-
# 缓冲队列中线程的空闲时间
thread.keep_alive_seconds: 100
sc:
cloud:
# debug: true
dev: true
task:
core-pool-size: 20
max-pool-size: 50
queue-capacity: 200
keep-alive-seconds: 3000
thread-name-prefix: sc-task-executor-
用法:
要现在启动类和配置类中添加@EnableAsync注解
然后在需要异步的方法中添加@Async注解将方法异步化
具体方法中的线程池用法:
@Resource(name = "taskExecutor")
private Executor executor;
//在对应的方法中使用
executor.execute(() -> {
//逻辑
});