首先说下我这边的业务场景,在接收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(() -> {
            //逻辑
        });